Smart cast to non-null invalidated by the elvis operator?


#1

I just recently heard about Kotlin and am very impressed so far. I like it so much I have converted two of my Android applications to Kotlin to learn it (one was Java, one was Scala). Coming from a mainly Python / C# 5.0 background I find it very easy to pick up and also very clean and easy to read.

One of my favorite features is how Kotlin handles null safety and intelligently smart casts to non-null types when you’ve eliminated the possibility with a check or ?.let {}. I especially like that intelliJ (Android Studio) will sometimes offer simplifications that I hadn’t thought of like:

val result = trySomeFunction() ?: return // result is smart-cast to non-nullable

or

fun function(val intent: Intent?) {
    val intent = intent ?: return // intent is now non-nullable

I was surprised, however, that the following did not work in the same way:

fun function(val intent: Intent?) {
    val action = intent?.action ?: return 

    intent.getParcableExtra(...)  //  compiler error because intent is nullable

As I understand it, if intent is null, the elvis operator short-circuits and the function ends, but there is no smart cast. I thought this might be a bug in the AndroidStudio plugin at first, but I get the same behavior from try.kotlinlang.org. Is there a reason I am missing that a smart cast cannot work in this situation?


#2

There has to be some limit on how in depth of an analysis Kotlin goes through to determine smart casts. Here you are returning if intent?.action is null which could be null if intent is null or if the intent’s action is null. This is only one level of indirection from intent being null, but what if you added more expressions in there? Where does it draw the line? They are smart casts not genius casts :wink:


#3

We have a couple of issues open about receiver smart casting after elvis calls and other conditional operators. See KT-4565 and its related issues.