Smart cast to 'Boolean' is impossible after value affectation [duplicate] - kotlin

This question already has answers here:
Smart cast to 'Type' is impossible, because 'variable' is a mutable property that could have been changed by this time
(12 answers)
Closed 4 years ago.
Error on the second println :
Smart cast to 'Boolean' is impossible, because 'r.isSquare' is a
mutable property that could have been changed by this time
fun main(args: Array<String>) {
val r: Rectangle = Rectangle(5,5)
println(r.isSquare)
r.isSquare = true
println(r.isSquare) // error but works with println(r.isSquare?:false)
}
data class Rectangle(var height: Int, var width: Int){
var isSquare: Boolean? = null
}
If it was null, it would print null like the first println, why do i have to do this ?
Edit 2
Thanks for all your answers, what i understand now :
First println is
println(message: Any?)
Second println is
println(message: Boolean)
Because r.isSquare = true make compiler trust that isSquare is Boolean and not anymore Boolean?
Edit2
Here is how i handle the compiler to keep trusting isSquare is Boolean?
fun main(args: Array<String>) {
val r: Rectangle = Rectangle(5, 5)
println(r.isSquare)
r.isSquare = true as Boolean? // if no cast, he will try wrong println signature
println(r.isSquare)
}
data class Rectangle(var height: Int, var width: Int){
var isSquare: Boolean? = null
}

Since the r.isSquare is a mutable property, the compiler cannot smart cast it to a non-null property after a null check.
You can use let:
r.isSquare.let { println(it) }
let reads the value of r.isSquare only once and it provides the same value as it inside the lambda. So you don't have to use ? or !! to access the boolean even after the null check.
From the Kotlin spec:
The language uses information about preceding checks for null, checks
for types (is, !is), safe call operators (?.) and Nothing-returning
expression to infer additional information about types of variable
(beyond that explicitly specified or inferred from initializers at
their declarations) that may be more specific in certain blocks or
even expressions. This information is then used to enable wider set of
operations on those expressions and to select more specific overloads.
fun main(args: Array<String>) {
var x : Any
x = ""
x.toUpperCase() // OK, smart cast to String
}
The first println uses this println(message: Any?)
Since you are assigning true to the isSquare next, the compiler tries to smart cast the isSquare to the Boolean type, when you try to print that. But it couldn't smart cast because the property is a mutable type.
If you remove the line, r.isSquare = true, then the compiler does not try to smart cast it to Boolean and uses the println with Any? as parameter.

In order for it to work you have to add a non null asserted call (!!) after your variable. Either r!!.isSquare or r.isSquare!!
fun main(args: Array<String>) {
val r: Rectangle = Rectangle(5,5)
println(r.isSquare)
r.isSquare = true println(r.!! isSquare)
}
data class Rectangle(var height: Int, var width: Int) {
var isSquare: Boolean? = null
}

As isSquare is a mutable property (var). It means between lines where do you write a value and then you read it, another thread can modify it and get a NPE because of that.
r.isSquare = true
//Another thread set r.isSquare = null
println(r.isSquare) // you get a null pointer exception
You must check the property nullability every time you work with nullable vars.

Because println() function in Android doesn't support Boolean?, and Boolean? with mutable property in kotlin cannot be unwrapped automatically by smart cast of Kotlin.
Try out String? or Int? or any types with mutable and nullable properties will get the same thing happen.

Related

Why do we need word get in String

My expectation:
I want to see something like that:
package com.example.myapplication
class ExampleGet {
val p2: String = "Black"
}
fun main(){
var ex = ExampleGet()
println(ex.p2)
}
I understand this example, it's work fine.
My problem
I don't know why do we need a word get in this class
package com.example.myapplication
class ExampleGet {
val p: String get() = "Black"
val p2: String = "Black"
}
fun main(){
var ex = ExampleGet()
println(ex.p)
println(ex.p2)
println(ex.p==ex.p2)
}
But I don't know what's difference between
Line 1
val p: String get() = "Black"
and
Line 2
val p2: String = "Black"
If we don't have any difference between Line 1 and Line 2 why do get() exist in kotlin? I ask because I have fond an example
package com.example.myapplication
import androidx.fragment.app.Fragment
import com.example.myapplication.databinding.FragmentThirdBinding
class ThirdFragment:Fragment() {
private var _binding : FragmentThirdBinding? = null
private val binding get() = _binding!!
}
I don't know why did people use
private val binding get() = _binding!!
but not
private val binding = _binding!!
Properties in Kotlin can have an initializer, a getter, and a setter, but all of them are optional.
When you write
val p2: String = "black"
the property p2 is initialized with value "black". It has an implicit getter that always returns the current value of the property, and it would have an implicit setter that sets that value, if it was a var and not a val.
When you write
val p: String get() = "black"
you defined an explicit getter for the property p that always returns "black". So, in this example it does not become clear what the difference is, because "black" is a constant value.
Let's consider instead the following example:
val p1 : String = System.nanoTime()
val p2 : String get() = System.nanoTime()
When you use property p1, it will always return the time in nanoseconds of the moment it was initialized.
However, when you use property p2, it will always return the time in nanoseconds of the moment, you are calling p2.
So, regarding your example with the property binding, the definition with getter instead of an initializer, allows to always get the value of the internal variable _binding instead of only its initial value. The variable _binding is called a backing property.
Short answer: both lines define a property, but one has an initialiser while the other overrides the getter method.
In Kotlin, a property always has a getter method (and, if it's mutable, a setter method). When you refer to the property (e.g. myExampleGet.p), you're actually calling the getter method. (This is unlike Java.) A property will usually (though not always) have a private field to store the value, as well (known as the ‘backing field’).
Let's take your two cases in reverse order. Your second case has an initialiser, which is the most common form:
val p2: String = "Black"
This defines a property called p2, of type String, and assigns it the initial value "Black". You don't specify a setter method, so you get the default one, which just returns the backing field.
Your first case provides a setter method, instead of an initialiser:
val p: String get() = "Black"
This says that p is a property with type String, and that its getter method always returns the hard-coded value "Black".
This property doesn't need a backing field, because it would never be used.
So, what's the difference? In your example, very little. The main one is that every instance of ExampleGet has a field called p2, all of which contain the same reference (to the hard-coded string); they do not have a field p. So p is more memory-efficient.
However, in other situations, the difference is much less subtle! For example, the setter might not return a constant value, e.g.:
class ExampleGet {
val p: String get() = (++counter).toString()
val p2: String = (++counter).toString()
private var counter = 0
}
Here p2 would always have the same value it was initialised with (probably "1"), while p would give a different value each time: "2", then "3", then "4", and so on. (In practice, such a getter might perform some calculation on another property, or get it from some other source, but I hope this illustrates the point.)
Another situation making the difference obvious would be if the properties were mutable, i.e. var instead of val:
class ExampleGet {
var p: String get() = "Black"
var p2: String = "Black"
}
Here p2 would behave as you expect, returning the value you set:
val eg = ExampleGet()
println(eg.p2) // prints "Black"
eg.p2 = "White"
println(eg.p2) // prints "White"
But p would always return the same value:
eg.p = "White"
println(eg.p) // prints "Black"
(I think p would have a backing field in this case, which would store whatever value you set — but you'd never be able to see that value, because the setter would always return the hard-coded value.)
So the two cases are doing very different things, even though the effect is practically the same in the code in the question.
The difference you can see in decompiled Kotlin into Java code
So the code:
class ExampleGet {
val p: String get() = "Black"
val p2: String = "Black"
}
Become (Java):
public final class ExampleGet {
#NotNull
private final String p2 = "Black";
#NotNull
public final String getP() {
return "Black";
}
#NotNull
public final String getP2() {
return this.p2;
}
}
As you can see, val with get() become method returning value.
In my practice, I use variable shadowing to make user's code operate with different type, for example:
val publicValue: List<String>
get() = _privateValue
private val _privateValue: MutableList<String>...
It's been covered, but specifically for this stuff in your example:
private var _binding : FragmentThirdBinding? = null
private val binding: FragmentThirdBinding get() = _binding!!
I've been explicit about the types here - _binding is nullable, binding is non-null. binding is a getter that's casting the value of _binding to another type (the non-null equivalent). When people access binding, they "don't have to worry" about it being null, don't have to do any null handling etc.
Here's the thing - none of that makes any sense. It's only non-null because they've asserted that with the !! operator (which should generally be seen as a red flag - it's circumventing the nullability checker, telling it it's wrong).
What they're probably doing is assigning binding later (e.g. in onCreate), but the variable needs to be initialised to something before that, so they make it nullable and set it to null as a placeholder. But that makes binding nullable, and it needs to be null-checked every time, even if in reality, it will always have been assigned to something by then, and will never be null when something tries to use it.
So this solution creates another placeholder variable, called _binding, which is nullable. But the code accesses binding instead, which is non-null. It's all based on the idea that _binding definitely won't be null when accessed, so the !! will always be valid.
This situation is what lateinit is for though:
lateinit var binding: FragmentThirdBinding
Same thing - a promise to assign it before it's read, no need for nullability. It's a var instead of a val but that's rarely going to matter, and not for something like this where you're only going to set it once anyway. To me it's more readable, uses the language features instead of working around them (!!), etc.
I'm not sure where the "cast a nullable field" pattern came from, it looks a lot like the way you're recommended to expose a private MutableLiveData as a public immutable LiveData type instead, so I'm not sure if people are just adapting that. Maybe there's a benefit to it I don't know about!

Extension method, when called on a null object, is called on the wrong type

fun main() {
val set: Set<Int>?
set = null
val emptySet: Set<Int> = set.orEmpty()
}
Can't figure out why even when explicitly typing the set variable as Set <Int>? the compiler considers that in the extension method set.orEmpty () set - is a string and, accordingly, crashes with an error:
Kotlin: Type mismatch: inferred type is String but Set was expected
But when declaring and initializing in one line, everything happens correctly:
fun main() {
val set: Set<Int>? = null
val emptySet: Set<Int> = set.orEmpty()
}
The behavior you're observing can be explained by the interaction of two Kotlin features:
first, the type of set variable is narrowed to Nothing? as a result of a smart cast after the assignment of null value to it. The smart cast after an assignment can be useful in cases when it narrows variable type to a more specific type, but narrowing to Nothing? does more harm than good.
second, among all overloads of orEmpty function available for a value of type Nothing?, the non-generic one String?.orEmpty() is chosen due to the specific rule of Kotlin overload resolution: a non-generic candidate is preferred to generic ones.
This behavior indeed can be puzzling, so I've reported this problem as KT-50661.
I think this is related to the fact that the compiler is not so smart that it could deduce that the code set = null will be executed exactly once – it could be zero times or more than once.
If you know that it will run exactly one, you can tell the compiler by using a feature called kotlin.contracts:
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
#ExperimentalContracts
fun main() {
val set: Set<Int>?
once { set = null }
val emptySet: Set<Int> = set.orEmpty()
}
#ExperimentalContracts
fun once(lambda: () -> Unit) {
contract { callsInPlace(lambda, InvocationKind.EXACTLY_ONCE) }
lambda()
}
See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.contracts/

Kotlin smart cast not working with extensions functions

I am trying check nullable object with extension function, but smart casting not work after calling this function.
fun <T> T?.test(): T = this ?: throw Exception()
val x: String? = "x"
x.test()
x.length // Only safe (?.) or non-null asserted (!!) calls are allowed on a nullable receiver of type String?
Is it a Kotlin bug? If not, why there is no implicit casting?
As #Madhu Bhat mentioned in comment above, your variable 'x' is still nullable.
You may use your function simply like this:
x.test().length
Otherwise you can check for null by following inline function and then perform any functions directly on the variable. (Note the usage of 'contract' and annotations '#ExperimentalContracts')
#ExperimentalContracts
fun <T> T?.notNull(): Boolean {
contract {
returns(true) implies (this#notNull != null)
}
return this != null
}
Now you can use this function like this
if(x.notNull()){
x.length
}
But its not seems so useful if your using this function just to check nullability.
Check here to know more about Kotlin contracts

How to store boolean property for Parcelable interface?

I have a data object, User. One of the properties of User is a Boolean. I can't figure out how to store this Boolean as there is no such writeBoolean() provided out of the box.
From what I've searched online, one way of storing the Boolean property is to use the writeInt() method and a ternary operator.
So I tried it here:
data class User(val contactNumber: String,
val email: String,
val fullName: String,
val isAdmin: Boolean,
val organization: String,
val unitNumber: String) : Parcelable {
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeString(contactNumber)
dest?.writeString(email)
dest?.writeString(fullName)
dest?.writeInt(isAdmin ? 1 : 0)
dest?.writeString(organization)
dest?.writeString(unitNumber)
}
}
But this syntax seems to only work with Java and not in Kotlin. I'm getting a compiler error indicating Unexpected tokens (use ':' to separate expressions on the same line. How do I accomplish this in Kotlin?
The ternary operator is not supported in kotlin
Use if-else instead
writeInt(if(isAdmin) 1 else 0)
Im using writeValue instead, it also usefull for nullable variables
dest.writeValue(this.booleanVar)
booleanVar = parcel.readValue(Boolean::class.java.classLoader) as? Boolean?
if it could be nullable and if not add ?: false
upd: as pointed in other answers dest variable cannot be null. afaik it marked as nullable after code converting using Android Studio. If you use that feature better to double check your code because of convertation could work not properly sometimes.
About ?. in general. You can rewrite it with let operator
dest?.let { it ->
it.write(....)
or even better
dest ?: retrun
The syntax for Java's isAdmin ? 1 : 0 in Kotlin is if (isAdmin) 1 else 0.
dest can't reasonably be null, so you can change its type to Parcel and all the ?. to ..
But the real answer is: use #Parcelize and let the compiler generate all that code, so you can't forget to change it when you add new properties, or get the order wrong, or...
1.) use this handy extension function:
fun Parcel.readBoolean(): Boolean = readByte() > 0
fun Parcel.writeBoolean(bool: Boolean) {
writeByte((if (bool) 1 else 0).toByte())
}
2.) in
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest: Parcel! is a platform type, so if you know that it will never be null, then there is zero reason to specify it as a nullable type.
Use override fun writeToParcel(dest: Parcel, flags: Int) { instead.

How to pass nullable type into function that takes a non null type?

Is this possible if I do a null check before passing? For example:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
if (num != null) doSomething(num)
}
fun doSomething(number: Int) {
...
}
I don't understand why the compiler won't allow me to pass a nullable even though I check that it's not null first. Can anyone explain?
NOTE: starting from compiler version 1.0 beta the code in question works as is
The compiler can tell if the variable is mutated between check and use, at least in case of local variables like in this question, and in some other cases. See Jayson's answer for details.
http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-keyword--in-conditions says
The compiler tracks the information about the [null] check ... this only works where b is immutable (i.e. a local val or a member val which has a backing field and is not overridable), because otherwise it might happen that b changes to null after the check.
So something like this should work:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
fun doSomething(number: Int) {
...
}
Of course, it would be nicer to rewrite "stuff happens" in such a way that you could make num into a val in the first place.
In current Kotlin (1.0 beta or newer) you do not have this issue anymore. Your code would compile. A local variable that is val or var can safely Smart Cast since the compiler can determine if the value could have mutated or not (on another thread for example).
Here is an excerpt from another Stack Overflow question that covers more aspects of nullability and Kotlin's operators for dealing with them.
More about null Checking and Smart Casts
If you protect access to a nullable type with a null check, the compiler will smart cast the value within the body of the statement to be non nullable. There are some complicated flows where this cannot happen, but for common cases works fine.
val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
// allowed to reference members:
possiblyXyz.foo()
// or also assign as non-nullable type:
val surelyXyz: Xyz = possibleXyz
}
Or if you do a is check for a non nullable type:
if (possibleXyz is Xyz) {
// allowed to reference members:
possiblyXyz.foo()
}
And the same for 'when' expressions that also safe cast:
when (possibleXyz) {
null -> doSomething()
else -> possibleXyz.foo()
}
// or
when (possibleXyz) {
is Xyz -> possibleXyz.foo()
is Alpha -> possibleXyz.dominate()
is Fish -> possibleXyz.swim()
}
Some things do not allow the null check to smart cast for the later use of the variable. The example above uses a local variable that in no way could have mutated in the flow of the application, whether val or var this variable had no opportunity to mutate into a null. But, in other cases where the compiler cannot guarantee the flow analysis, this would be an error:
var nullableInt: Int? = ...
public fun foo() {
if (nullableInt != null) {
// Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
val nonNullableInt: Int = nullableInt
}
}
The lifecycle of the variable nullableInt is not completely visible and may be assigned from other threads, the null check cannot be smart cast into a non nullable value. See the "Safe Calls" topic below for a workaround.
Another case that cannot be trusted by a smart cast to not mutate is a val property on an object that has a custom getter. In this case the compiler has no visibility into what mutates the value and therefore you will get an error message:
class MyThing {
val possibleXyz: Xyz?
get() { ... }
}
// now when referencing this class...
val thing = MyThing()
if (thing.possibleXyz != null) {
// error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
thing.possiblyXyz.foo()
}
read more: Checking for null in conditions
You can use let to simplify the code. The kotlin scope function introduces a local variable in the context of "num". No need to declare temporary variable numVal.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
num?.let{
doSomething(it)
}
}
Which works same as below but simpler and cleaner.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
Use can use Scoping function let or apply along with null safe operator ?.
fragmentManager?.let{
viewPager.adapter = TasksPagerAdapter(it)
}
This way you can pass a nullable type to a non-nullable type parameter