1

Consider this piece of code:

var foo: Foo? = null

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

If I omit the two !! I get this error:

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

This is about concurrency, right? Well, there is no concurrent code that might change the value of foo.

Of course, it works with the two !!. However, I was wondering if this is the most idiomatice way or if there is a better way, without the two !!.

I know I could just foo?.bar() in this particular case. But the question is about whether I can treat foo as Foo instead of Foo? somehow after I've checked that it's not null.

Todd
  • 30,472
  • 11
  • 81
  • 89
user1785730
  • 3,150
  • 4
  • 27
  • 50
  • not really, your options are assigning it to a `val` within function scope, or use one of scoping functions (`let`, `run`, `apply`, `also`) – Pawel Aug 14 '19 at 22:52
  • How would I assign it to a val within function scope, so that the val would be of type Foo (not Foo?)? – user1785730 Aug 15 '19 at 00:09
  • 3
    "_This is about concurrency, right? Well, there is no concurrent code that might change the value of `foo`_". **You** may know that there's no concurrency, but the **compiler** cannot guarantee that. – Slaw Aug 15 '19 at 01:43
  • 2
    @user1785730, the `val` will be of type `Foo?`. However, now smart cast will work and you won't need `!!` in the code. –  Aug 15 '19 at 03:20

1 Answers1

3

Well, this piece of code works if foo is a local variable. I guess, your code looks a little bit different and foo is a field of a class. The solution is simple: use let:

foo?.let {
    it.bar()
}

let "captures" the values of a variable so that any modifications to the original one have no effect in the passed lambda. And safe call is used here to invoke let only for non-null values.

madhead
  • 31,729
  • 16
  • 153
  • 201