a?.let { block() } is indeed equivalent to if (a != null) block().
This also means that if a is a mutable variable, then:
a might be reassigned after the null check and hold a null value when block() is executed;
All concurrency-related effects are in power, and proper synchronization is required if a is shared between threads to avoid a race condition;
However, as let { ... } actually passes its receiver as the single argument to the function it takes, it can be used to capture the value of a and use it inside the lambda instead of accessing the property again in the block(). For example:
a?.let { notNullA -> block(notNullA) }
// with implicit parameter `it`, this is equivalent to:
a?.let { block(it) }
Here, the value of a passed as the argument into the lambda is guaranteed to be the same value that was checked for null. However, observing a again in the block() might return a null or a different value, and observing the mutable state of the given instance should also be properly synchronized.
acan be null when the block is executed, butitcan not. I.e. it's equivalent toval copy = a; if (copy != null) { block(copy) }- JB Nizetif (a != null) { a.someFunction() }) - marstranawas of typeInt?):Smart cast to 'Int' is impossible, because 'a' is a mutable property that could have been changed by this time- marstran