Just curious: In Kotlin, I would love to get some val that can be initialized by lazy, but with a parameter. That's because I need something that's created very late in order to initialize it.
Specifically, I wish I had:
private lateinit val controlObj:SomeView
or:
private val controlObj:SomeView by lazy { view:View->view.findViewById(...)}
and then:
override fun onCreateView(....) {
val view = inflate(....)
controlObj = view.findViewById(...)
or in the 2nd case controlObj.initWith(view)
or something like that:
return view
I cannot use by lazy
because by lazy
won't accept external parameters to be used when initialising. In this example - the containing view
.
Of course I have lateinit var
but it would be nice if I could make sure it becomes read only after setting and I could do it in one line.
Is there a pretty clean way to create a read only variable that initializes only once but only when some other variables are born? Any init once
keyword? That after init the compiler knows it's immutable?
I am aware of the potential concurrency issues here but if I dare to access it before init, I surely deserve to be thrown.
You can implement own delegate like this:
class InitOnceProperty<T> : ReadWriteProperty<Any, T> {
private object EMPTY
private var value: Any? = EMPTY
override fun getValue(thisRef: Any, property: KProperty<*>): T {
if (value == EMPTY) {
throw IllegalStateException("Value isn't initialized")
} else {
return value as T
}
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
if (this.value != EMPTY) {
throw IllegalStateException("Value is initialized")
}
this.value = value
}
}
After that you can use it as following:
inline fun <reified T> initOnce(): ReadWriteProperty<Any, T> = InitOnceProperty()
class Test {
var property: String by initOnce()
fun readValueFailure() {
val data = property //Value isn't initialized, exception is thrown
}
fun writeValueTwice() {
property = "Test1"
property = "Test2" //Exception is thrown, value already initalized
}
fun readWriteCorrect() {
property = "Test"
val data1 = property
val data2 = property //Exception isn't thrown, everything is correct
}
}
In case when you try to access value before it is initialized you will get exception as well as when you try to reassign new value.