As you all know, it’s “impossible” in Kotlin to add actual state to a final class in a mixin-like-fashion. Well, apparently there is a way. The simplest way to think of how to achieve this is to just have a map that maps between the object and the value of the specific property that you want to add. The problem with that is that it prevents gc on the actual object, which is obviously a HUGE performance impact. But, we can still use weak references with almost no overhead. So… here’s the code and enjoy ig:

import kotlinx.coroutines.launch import kotlin.reflect.KProperty class Example { override fun toString() = "Example Class" } interface IWeakReference<T> { val referent: T? fun clear() } open class JavaWeakReference<T>(value: T) : IWeakReference<T> { protected val queue = java.lang.ref.ReferenceQueue<T>() private val actualWeakRef = java.lang.ref.WeakReference<T>(value, queue) override val referent get() = actualWeakRef.get() override fun clear() { actualWeakRef.clear() } } interface WeakKeyReference<K, V> : IWeakReference<K> { val map: MutableMap<WeakKeyReference<K, V>, V> } class JavaWeakKeyReference<K, V>(key: K, override val map: MutableMap<WeakKeyReference<K, V>, V>) : JavaWeakReference<K>(key), WeakKeyReference<K, V> { init { kotlinx.coroutines.GlobalScope.launch { queue.remove() map.remove(this@JavaWeakKeyReference) } } } class ExtendedState<T> { private val map = mutableMapOf<WeakKeyReference<Any, T>, T>() operator fun getValue(thisRef: Any?, prop: KProperty<*>): T? = thisRef?.let { map[map.findWeakReferenceForKey(thisRef)] } operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: T) { val key: WeakKeyReference<Any, T> = thisRef?.let { map.findWeakReferenceForKey(thisRef) ?: JavaWeakKeyReference(thisRef, map) } ?: return map[key] = value } } fun <K, V, R : IWeakReference<K>> MutableMap<R, V>.findWeakReferenceForKey(key: K): R? { for ((currentKey, _) in this) { if (currentKey.referent == key) { return currentKey } } return null } var Example.p: String? by ExtendedState() fun main() { val examples = sequence{ var i = 0 while (true){ yield(Example().apply { p = i.toString() }) i++ } } examples.take(10000).toList().apply { forEach{ println(it.p) }}.asReversed().forEachIndexed { index, example -> if(index % 5 == 0) println(example.p) } }