Jeffrey Blattman
Jeffrey Blattman

Reputation: 22637

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?

Upvotes: 2

Views: 1451

Answers (3)

Alexey Romanov
Alexey Romanov

Reputation: 170713

In case where the condition is not just a function call, e.g.

foo != null && foo.bar() > 0

you can use let or run:

if (foo.let { it != null && it.bar() > 0 }) { ... }

if (foo.run { this != null && bar() > 0 }) { ... }

Upvotes: 1

Tenfour04
Tenfour04

Reputation: 93531

In this case, a null-safe call returns a Boolean? so you can check if it equals true:

if (foo?.bar() == true) {

}

If you need non-null foo inside the conditional, then you can use the common ?.let idiom.

foo?.let { foo ->
    if (foo.bar()) {
    
    }
}

If you know it’s only accessed on this same thread, the !! operator would be safe after the null check, but ?.let is more idiomatic so easier to follow once you’re used to reading Kotlin.

Upvotes: 3

Silvio Mayolo
Silvio Mayolo

Reputation: 70257

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.

Upvotes: 2

Related Questions