https://kotlinlang.org logo
#announcements
Title
# announcements
p

poohbar

12/09/2019, 6:17 PM
Why does the smart-casting not work here? And how would you solve it?
Copy code
fun main() {
    var value: Any? = "hello"

    if (value != null) {
        for (i in 1..10) {
            value = nonNullFoo(value) // smart casting fails
        }
    }
}

fun nonNullFoo(obj: Any): Any {
    return "World"
}
l

LeoColman

12/09/2019, 6:18 PM
I believe it fails because
value
might have been changed and the compiler can't guarantee it wasn't
Personally, I would solve it with a beautiful
!!
Because I'm smarter than the compiler in this case, and I'm sure it isn't null
p

poohbar

12/09/2019, 6:19 PM
value
is only every assigned the result of
nonNullFoo
which is
Any
I guess the compiler just can't see that far
l

LeoColman

12/09/2019, 6:19 PM
the compiler just can't see that far
I believe that's exactly it
The compiler can't trust that you didn't change
value
inside the for, I think
p

poohbar

12/09/2019, 6:20 PM
thanks
n

nikolaymetchev

12/09/2019, 6:22 PM
You could use
value?.let {...}
l

LeoColman

12/09/2019, 6:23 PM
I think
let
will mask the fact that
value
can never be null. It will give the obvious possibility that it is null sometimes
1
h

hallvard

12/09/2019, 7:16 PM
The compiler looks further, actually. Who knows if
value
is being changed by another thread somewhere else in the code? Or even from some included dependency library? Contracts is the way to solve this.
p

poohbar

12/09/2019, 7:21 PM
how could
value
be changed by another thread when it's a local variable?
l

LeoColman

12/09/2019, 7:21 PM
Value is local, other threads cant touch the reference
h

hallvard

12/09/2019, 7:38 PM
Admittedly! Don't know why I missed that, I just answered with the autopilot turned on, since this question arises from time to time, and mostly with code where a different thread actually may touch the
value
... I decompiled the code to take a look at the generated bytecode, and am now just as stumped as you are. My only explanation for this is that the compiler must be as blind as I was, and/or didn't dare insert a
Contract
all by itself.
We missed the important part because the red highlighting was in the wrong place!
The problem is that nonNullFoo accepts
Any
, not
Any?
. So it's the nonNullFoo function that should have had the red underlining, in my opinion ...
t

tseisel

12/10/2019, 2:11 PM
@poohbar I just wrote the same code in a scratch file and the smart cast works just as intended. This should only fail when dealing with
var
properties, what version of Kotlin are you using ?
4 Views