Feedback Request: Implementing a mutableLazy Delegate in Kotlin for Thread-Safe Mutable Properties

I’ve been exploring Kotlin’s lazy functionality and realized it’s primarily designed for immutable variables. However, I needed a similar mechanism for mutable properties. As a result, I devised a mutableLazy delegate pattern that aims to support mutability while preserving thread safety through double-checked locking. Here’s the implementation:

 import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty fun <T> mutableLazy(initializer: () -> T): MutableLazy<T> { return MutableLazy(initializer) } class MutableLazy<T>(initializer: () -> T) : ReadWriteProperty<Any?, T> { companion object { private object UNINITIALIZED } u/Volatile private var value: Any? = UNINITIALIZED private var initializer: (() -> T)? = initializer private val lock = Any() override fun getValue(thisRef: Any?, property: KProperty<*>): T { val _v1 = value if (_v1 != UNINITIALIZED) { u/Suppress("UNCHECKED_CAST") return _v1 as T } return synchronized(lock) { val _v2 = value if (_v2 != UNINITIALIZED) { u/Suppress("UNCHECKED_CAST") _v2 as T } else { val typedValue = initializer!!() value = typedValue initializer = null // Clear the initializer to allow garbage collection of the lambda typedValue } } } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { synchronized(lock) { this.value = value } } } 

Usage example:

 object XXXOptions { private const val THEME = "THEME" val theme: Theme by mutableLazy { val sharedPreferences = XXXApplication.instance.getSharedPreferences() val moshi = Moshi.Builder().build() val jsonTheme = sharedPreferences.getString(THEME, null) if (!jsonTheme.isNullOrBlank()) { moshi.adapter(Theme::class.java).fromJson(jsonTheme)?.let { return@mutableLazy it } } return@mutableLazy PREFERRED_THEME } ... } 

I’m reaching out for insights on two aspects:

  1. Design Review: Is the implementation of MutableLazy, particularly the use of double-checked locking for ensuring thread safety, correctly designed? Are there any potential pitfalls or improvements that could be suggested?

  1. Companion Object Necessity: The UNINITIALIZED value is encapsulated within a companion object to signify its unique state. However, given that UNINITIALIZED is already a singleton, is there a strong justification for using a companion object? Could it be omitted, or is there a better practice for handling such a scenario?

I appreciate any feedback or alternative approaches that could enhance this implementation. Thank you!

Thank you.

submitted by /u/yccheok
[link] [comments]