0

I try to run the following code, but the code can't pass compile, I get the error:

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

Why?

class MyClass1(var i: Long?) {

    fun change(): Long? {
        if (i != null) {
            return i + 10L
        } else {
            return 5L
        }
    }
}

I wrote the code MyClass2 in Java, it can work well, why?

class MyClass2{
    private Long i;

    public MyClass2(Long k){
       i=k;
    }

    public Long change(){
       if (i!=null){
           return i+10L;
       }else {
           return 5L;
       }
    }
}
Neil
  • 14,063
  • 3
  • 30
  • 51
HelloCW
  • 843
  • 22
  • 125
  • 310
  • 1
    `i` is not local to `change`. So something outside `change` could have modified `i` inbetween the null-check and where you try to use `i` for `return`. – Michael Nov 20 '17 at 07:04

1 Answers1

6

Because i is a var, it can theoretically be changed by another thread between your null check and the plus-operation.

You can use the let function to solve it. It will "capture" the value of i by giving it as a parameter to let.

fun change(): Long? {
    return i?.let { it + 10L } ?: 5L
}
marstran
  • 26,413
  • 5
  • 61
  • 67
  • Thanks! I updated my question, the same code can work well when I write it in java, would you please have a look? – HelloCW Nov 21 '17 at 00:52
  • @HelloCW Java doesn't have the concept of nullable types. It will therefore compile even though it has the same problem as the Kotlin code. The Java code will fail if some other thread would change `i` to `null` between the null check and the plus operation. – marstran Nov 21 '17 at 10:18
  • There is a difference between your Java and Kotlin code though. In your Kotlin code, `i` is public, while it is private in your Java code. – marstran Nov 21 '17 at 10:19
  • Thanks! Do you mean that it will work when I change my Kotlin code as `class MyClass1(private var i: Long?) {...}` – HelloCW Nov 21 '17 at 10:55
  • No, the methods on the class can still be called by several threads at the same time. The compiler isn't smart enough to understand that none of them has a way to change `i` to `null`. I would rather try to change `i` to a `val`. – marstran Nov 21 '17 at 12:44
  • Thanks , Could you write a sample code about how several threads the class at the same time ? – HelloCW Nov 22 '17 at 13:35
  • That wouldn't serve any purpose. What I'm describing is a race condition. You can read more about it in this answer: https://stackoverflow.com/a/34550/4137489 – marstran Nov 22 '17 at 13:45