1

I expected that the type of a variable is promoted to a non-null type after a not-null check (like in the Dart language).

val someMap = mapOf("a" to 0L)
val a = someMap['a'] // a is of type Long?
if (a != null) {
    val b = a // b is of type Long? and not of type Long. Why? 
}

Can someone explain why this is not the case? Just a matter of taste of the language designers?

4 Answers4

3

Since there is smart-casting, it doesn't matter. It will allow you to use members of a or b inside the if statement without null-safe calls (?.) or null assertions (!!). You can also safely declare b to be a Long without the compiler complaining:

if (a != null) {
    val b: Long = a
}

It is I think a design choice for how implicit types should be inferred that b's type must be explicitly declared if you want it to be considered non-nullable. This is only relevant if passing it to a function with generics, since there is smart-casting.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • That is indeed true. I just wonder why IntelliJ does not highlight `a` as being smart-casted without explicitly defining the type of `b` as `Long`. – João Dias Dec 08 '21 at 15:55
  • I think the type of `b` is still considered `Long?` if you let it take the implicit value of `a`. This might be relevant if you passed it to a generic function. It's a behavior choice of the designers for it to only smart-cast if it explicitly needs to. Smart-cast highlighting in the IDE also seems buggy. Like if `a` is a `var` and I set it to null in the if-statement and then `println(a)`, it highlights `a` like it's being smart-cast even though it's null and the compiler complains if I try to use one of its members. – Tenfour04 Dec 08 '21 at 15:57
  • Good point, that might be the case indeed. I would upvote your answer but I've run out of votes for today. – João Dias Dec 08 '21 at 16:02
1

What you can do instead of explicit null check is using let{} as follows:

val someMap = mapOf('a' to 0L)
val a = someMap['a'] // a is of type Long?
a?.let {
    val b = it // b is of type Long
}
João Dias
  • 16,277
  • 6
  • 33
  • 45
  • Mmm, this is a fairly common workaround. It also handles cases where the variable is a mutable field (and so could be modified by another thread in between the two uses), and/or where a more complex expression is being tested. – gidds Dec 08 '21 at 20:51
0

It is called smart casting, basically Kotlin is smart enough to determine that variable can no longer be null after check. More detail and can be found here if you are interested

Vojin Purić
  • 2,140
  • 7
  • 9
  • 22
0

As to why, only the creators of kotlin can know. But what you can do is this if you want a Long instead of Long? there is this

val b = a!!
Ivo
  • 18,659
  • 2
  • 23
  • 35