Ok, I thought about the syntax a bit, and that’s how I would see it:
delegate class LazyStuff <T> by { init: (() -> T) -> lazy(init) } {
delegate val someNum by { 42 }
delegate val someString by { "Hello" }
delegate val someImage by { BufferedImage(4096, 4096, TYPE_INT_ARGB) }
delegate val someData by { (0..999999).map { it*it } }
}
Which would be equivalent to:
final class LazyStuff {
private fun <T> _delegateFactory(init: ()->T): Lazy<T> {
return kotlin.lazy(init)
}
val someNum: Int by _delegateFactory { 42 }
val someString: String by _delegateFactory { "Hello" }
val someImage: BufferedImage by _delegateFactory { BufferedImage(4096, 4096, TYPE_INT_ARGB) }
val someData: List<Int> by _delegateFactory { (0..999999).map { it*it } }
}
As previous examples were pretty simple, let me present a bit more complex one:
object DataStorage {
private val data: MutableMap<String, Any?> = mutableMapOf()
fun store(key: String, value: Any?) {
data[key] = value
}
fun <T> get(key: String): T? = data[key] as T?
}
class DataStorageDelegate <T>(private val dataStorage: DataStorage, private val defaultValue: T? = null) {
operator fun getValue(thisRef: Any, prop: KProperty<*>): T? {
return dataStorage.get(prop.name) ?: defaultValue
}
operator fun setValue(thisRef: Any, prop: KProperty<*>, value: T?) {
dataStorage.store(prop.name, value)
}
}
delegate class DataAccessor <T> (dataStorage: DataStorage) by {
defaultValue: T? -> DataStorageDelegate(dataStorage, defaultValue)
} {
delegate var configurationJson: String?
delegate var logoImage: BufferedImage?
delegate var welcomeMessage: String? by "Hello"
}
Where the last class would translate to::
final class DataAccessor(private val dataStorage: DataStorage){
private fun <T> _delegateFactory(defaultValue: T?): DataStorageDelegate<T> {
return DataStorageDelegate(dataStorage, defaultValue)
}
var configurationJson: String? by _delegateFactory(null)
var logoImage: BufferedImage? by _delegateFactory(null)
var welcomeMessage: String? by _delegateFactory("Hello")
}
Notice that we get rid of private val dataStorage
reference in the class constructor, and that encourages encapsulation. Also I proposed to be able to omit by xxx
, if one wants to pass null
, but that’s optional.
I propose that we could pass delegate factory as follows:
- existing method (as in original example) - need to specify generics and proper overload
- lambda (
DataStorage
example)
- anonymous function - with special exception to allow default arguments