Can someone explain me the concept of frozen ? I c...
# kotlin-native
f
Can someone explain me the concept of frozen ? I created a class that contains a MutableMap, I got a frozen exception when I try to put an element inside
g
This is “truly immutable” data, “truly” means that immutability checked by runtime And if you freeze MutableMap or some class with
var
properties, runtime will not allow to change it. It required to safely pass data between threads
y
Ensuring immutability in runtime.
f
ok thanks, so how can I achieve a map.put if it’s frozen ? 😅
g
You cannot
this is whole point of frozen
f
How can I ensure it will not be frozen ?
g
and you cannot unfreeze data
f
😢
so I cannot have a mutable map in kotlin native ?
g
You can
but you cannot share this map to different threads without freezing
they cover main concepts
y
some class with
var
properties, runtime will not allow to change it.
In addition, some class with
val
properties are not allowed to be accessed by several threads either without being frozen.
g
yes, correct, I just mean that you cannot change anything mutable
👍 1
Yuya right, val also can contain some mutable object which will be also recursively frozen Or even immutable, but runtime doesn’t know this, so you must explictly mark it as frozen
y
nice 🎉
f
it’s because in my case it uses MutableDictionary in swift/ObjC, which needs to net be marked at
let
to be mutable ?
If I use a
var myMap = mutableMap<String, String>()
, in kotlin native, it will be frozen ?
g
no, it will not
f
in my case it’s frozen
g
mutableMap? Do you mean mutableMapOf?
f
mutableMapOf *
g
Maybe you could give more context This works properly on K/N for me, just checked
Copy code
fun main(args: Array<String>) {
    val myMap = mutableMapOf<String, String>()
    println(myMap) // {}
    myMap["foo"] = "bar"
    println(myMap) // {foo=bar}
}
f
ok 😕
I just tried to reproduce an event-bus like for kotlin multiplatform
in jvm, its works perfectly
and in native, I’ve got a frozen
g
Do you share mutable map over event-bus?
f
Copy code
@Suppress("UNCHECKED_CAST")
    fun <T> addObserver(observer: Any, key: String, block: (T) -> Unit) {
        val function: ((Any) -> Unit)? = block as? (Any) -> Unit
        function?.let {
            if(keyObservers.containsKey(key)){
                keyObservers[key]?.add(observer, function)
            } else {
                val keyObserver = KeyObservers<Any>()
                keyObserver.add(observer, function)
                keyObservers[key] = keyObserver
            }
        }
    }
nope
Copy code
private val keyObservers = mutableMapOf<String, KeyObservers<Any>>()
g
ohhh
I got it
it’s top level property
You cannot do this so simple
f
it’s because it’s a field ?
g
because this top level property can be accessed from different threads, so frozen by default
f
and not a parameter of the method ?
g
yes
f
😢
how to deal with this properly ?
g
You cannot have shared mutable state in Kotlin Native
But
if you want to use it from single thread, you can use ThreadLocal
Section “Global variables and singletons”
f
I need to annotate my field with
@kotlin.native.ThreadLocal
?
l
@florent If you don't need to share the map across threads, yes, you can do this
f
😕 my code was on the common module, I need to use actuals to add this annotation
g
One more solution, you library can use EventBus instance class, isntead of global one, so each user of this API decide how to use it ThreadLocal or single thread
actually, probably make sense to ask mark
@kotlin.native.ThreadLocal
as platform optional annotation
but in general yes, you should decide how to implement this global mutable state for each platform
f
thanks @gildor 🙂
j
Also good to know: use ensureNeverFrozen() to have an exception thrown for which code is freezing your values. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/ensure-never-frozen.html