Var, multithreading, and when() statement


#1

Here is the problem : I have a foo class and a bar class,

the bar class have a nullable var of Item (Item is an interface), and has a method that doStuff() with it

the foo class have an instance of a bar class, run a thread that write to the var item, and call bar’s doStuff() repeatedly

Here is the bit of code of to run that

import kotlin.concurrent.thread

fun loopingDaemonThread(action: () -> Unit) {
    thread(isDaemon = true) {
        while (true) {
            try {
                action()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}

class Foo {
    private val bar = Bar()
    init {
        loopingDaemonThread {
            //Furiously change bar's item
            bar.item = if (Math.random() > 0.5f) C() else null
        }
    }

    fun doStuff() {
        while(true) {
            bar.doStuff()
        }
    }
}

class Bar {
    interface Item

    var item: Item? = null

    fun doStuff() {
        when (item) {
            is B -> println((item as B).doBStuff())
            is C -> println((item as C).doCStuff())
            else -> println("null")
        }
    }
}

class B : Bar.Item {
    fun doBStuff(){}
}
class C : Bar.Item {
    fun doCStuff(){}
}

fun main(args: Array<String>) = Foo().doStuff()

The problematic part is this one

        fun doStuff() {
        when (item) {
            is B -> println((item as B).doBStuff())
            is C -> println((item as C).doCStuff())
            else -> println("null")
        }
    }

Where “item” can be null at any point even inside somethind like “is B”, so what’s the best way to deal with that? One solution would be to make a immutable copy of “item” and call the “when” statement on that copy instead, but i’m pretty there is better than that


#2

The short answer to your question is that you should copy the value to a local variable first.

The longer answer is that even if you do that, the code might not work the way you expect it to. This is because unless you use synchronisation, you might end up with unpredictable results when you read a variable in one thread that is simultaneously written in another.