Are smart casts and null checking on global var thread safe?

Let a is global variable of type A or field of current object of type A.

Is the following code thread safe?

if a is B { 
    a.methodOfB() 
}

and

if a != null { 
    a.methodOfA() 
}

a could be changed in other thread and these checks might not help.
Does Kotlin save checked value of a to local variable?

In Swift it’s done slightly in other way and I know that this is thread safe in Swift:

if let a = a { // null check and assignment to local variable `a`
   a.methodOfA()
}

and

if let a = a as? B  { // safe cast, check for null and assignment to local variable a. also it can be done with `where` construct, but it doesn't matter here
   a.methodOfB()
}

I believe they are:

var a: String? = null

fun useA() {
    if (a != null) {
        println(a.length)
                ^ Error:(8, 17) Kotlin: Smart cast to 'kotlin.String' is impossible, 
                  because 'a' is a mutable property that could have been 
                  changed by this time
    }
}

fun isA() {
    if (a is String) {
        println(a.length)
                ^ Error:(8, 17) Kotlin: Smart cast to 'kotlin.String' is impossible, 
                  because 'a' is a mutable property that could have been 
                  changed by this time
    }
}

The closest to what you want is probably this:

val ta = a
if (ta != null) {
    println(ta.length)
    // more statements working on ta
}

You can’t do it as compact as in your Swift example because you can’t declare variables in if statements. You also can’t use braces like this (val ta = a)?.let { ... }

You can accomplish something very close to the Swift version in Kotlin. You can either re-use the name of the outer variable as the name of the inner scoped one, or you can rename it, or you can use the implicit it reference:

a?.let { a ->
    a.methodOfA()
}

a?.let { localA ->
    localA.methodOfA()
}

a?.let { 
    it.methodOfA()
}

(a as? B)?.let { a ->
    a.methodOfB()
}

(a as? B)?.let { b ->
    b.methodOfB()
}

(a as? B)?.let {
    it.methodOfB()
}
1 Like

You’re right. I didn’t think of that.