Search code examples
kotlinkotlin-null-safety

Kotlin idiom: null-safe conditional?


In Java, I'd write something like this:

if (foo != null && foo.bar()) { ...

However Kotlin complains that:

Smart cast to 'Foo' is impossible, because 'foo' is a mutable property that could have been changed by this time

I think it's saying what I wrote isn't thread-safe. However, in the context where I'm using it I know it is as this will always be invoked on a single thread.

Yes foo needs to be mutable. I realize that making foo a val would solve this but that is not possible here.

What's the correct idiom in Kotlin to handle this case?


Solution

  • The trick is to use Kotlin's excellent null-safety operators to avoid having to do redundant checks.

    First, we use the safe-call operator.

    foo?.bar()
    

    This is a Boolean? (i.e. a nullable Boolean) which is null if foo is null, or the result of bar() if not. Now, a Boolean? is not a valid condition in an if statement, obviously, so we need to provide a "default" value of false. We do that using the amusingly-named Elvis operator

    if (foo?.bar() ?: false) { ... }
    

    If foo is null, then foo?.bar() is null, and ?: returns the value of the right-hand side, i.e. false. If foo is non-null, then foo?.bar() is the result of calling bar() on foo, and (assuming that result is also non-null), ?: returns the existing non-null Boolean value.