I was following along Kotlin's documentation at http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-in-conditions and tried adapting this example,
val b = "Kotlin"
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
to the case where b = null
. In an IntelliJ Idea Kotlin project I have an app.kt
with a main()
function defined as:
fun main() {
val b = null
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
}
However, when I run this, I get two compilation errors:
Information:Kotlin: kotlinc-jvm 1.3.20 (JRE 11+28)
Information:2019-02-02 15:07 - Compilation completed with 2 errors and 0 warnings in 1 s 921 ms
/Users/kurtpeek/IdeaProjects/HelloWorld/src/app.kt
Error:(3, 24) Kotlin: Unresolved reference: length
Error:(4, 37) Kotlin: Unresolved reference: length
I understand that the compiler is evaluating b.length
even though the first condition, b != null
, is false
. This surprises me because I thought that the first check was to 'short-circuit' the Boolean expression if needed and make the call to b.length
'safe'.
For example, in Python, you can do this:
In [1]: "foo" == "bar" and what.the.heck
Out[1]: False
which works even though what
is not defined, because the and
'stops' since "foo"
is not equal to "bar"
.
Is this indeed how Kotlin works? It seems like missing Python's 'short-circuiting' feature would be a limitation.
Kotlin's &&
operator will short circuit (just like Java's) but only at runtime. What you are experiencing is a compile time error. The big difference to remember especially when comparing Kotlin (or Java) to Python is that Kotlin and Java are statically typed and have a compilation phase. So you'll get a compilation error if the types don't match up.
Let's go through these one at a time...
val b = "Kotlin"
if (b != null && b.length > 0) {
...
}
In this case, Kotlin will correctly infer that b
is the type String
, because you clearly set it to a String ("Kotlin"). We should note here that the String
type cannot ever contain null. Knowing that, the b != null
part of your if
statement is unnecessary. However, after evaluating that (to true, always) it will evaluate b.length
because b
is a String
and therefore has a length
property. This example should compile fine (I didn't test it).
And next...
val b = null
if (b != null && b.length > 0) {
...
}
This code will not compile, let's go over why...
This code looks really similar but has one huge difference. In this case because you just set b
to null
, Kotlin is going to infer that b
is an Nothing?
. It has no information as to what type you want b
to be, and you've set it to null (and because it's a val
, it will always be null
). Because b
is null
, it makes b
nullable.
So, given that, when we compile b != null
, that will always fail, because b
can't ever be something that isn't null
. But wait! We're compiling now... and when we run into b.length
Kotlin will throw a compilation error because Nothing?
does not have a length
property!
Essentially, by setting b
to null
and not providing a type hint, Kotlin takes the only path it can to infer the type - Nothing?
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With