Please look at this code:
fun localVarNullSafety1(){
var number: Double? = 3.0
val sum = 2.0 + number // does not compile (Type mismatch: inferred type is Double? but Double was expected)
}
fun localVarNullSafety1(){
var number: Double? = null
number = 3.0
val sum = 2.0 + number // compiles fine
}
I think that the above code consists of semantically identical functions - local variables don't go outside the scope, and they are local to the executing thread. In my opinion there is no reason for the first function not to compile.
I think that Kotlin's smart cast should take variable initialization into account.
Do I miss something obvious?
This was discussed in KT-13663, and it remains an open ticket at the time of writing.
They were considering the more general case of (Note that T?
is a supertype of T
):
val x: Supertype = Subtype()
var y: Supertype = Subtype()
and decided that in the val
case, it doesn't make sense for x
to have the type Subtype
here, otherwise you could just not write the type annotation in the first place.
This could make sense for var
s though, but if smart casts are only implemented for var
s, then vars
and val
s would have inconsistent behaviour regarding their types:
val x: Supertype = Subtype()
var y: Supertype = Subtype()
// inconsistent:
x.someSubtypeStuff() // doesn't work, x is a Supertype
y.someSubtypeStuff() // works, y is smart casted to Subtype
And so they ended up not implementing smart casts for initialisation back then.
Since the ticket is still open, this feature may very well be implemented in a future version of Kotlin. It might support just var
s, both var
s and val
s, or just nullable types. Let's hope for the best!