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?
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.