Kotlin

Delegated Properties

Swift
                  class Example {
    var p: String by Delegate()
}
                
                    class Example {
    var p: String by Delegate()
}
                  
                  import kotlin.reflect.KProperty
​
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }
 
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}
                
                    import kotlin.reflect.KProperty
​
class Delegate {
    operator func getValue(thisRef: Any?, property: KProperty<*>) -> String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }
 
    operator func setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        print("$value has been assigned to '${property.name}' in $thisRef.")
    }
}
                  
                  val e = Example()
println(e.p)
                
                    let e = Example()
print(e.p)
                  
                  e.p = "NEW"
                
                    e.p = "NEW"
                  

Lazy

                  val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}
​
fun main() {
    println(lazyValue)
    println(lazyValue)
}
                
                    let lazyValue: String by lazy {
    print("computed!")
    "Hello"
}
​
func main() {
    print(lazyValue)
    print(lazyValue)
}
                  

Observable

                  import kotlin.properties.Delegates
​
class User {
    var name: String by Delegates.observable("<no name>") {
        prop, old, new ->
        println("$old -> $new")
    }
}
​
fun main() {
    val user = User()
    user.name = "first"
    user.name = "second"
}
                
                    import kotlin.properties.Delegates
​
class User {
    var name: String by Delegates.observable("<no name>") {
        prop, old, new ->
        print("$old -> $new")
    }
}
​
func main() {
    let user = User()
    user.name = "first"
    user.name = "second"
}
                  

Delegating to another property

                  class MyClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) {
    var delegatedToMember: Int by this::memberInt
    var delegatedToTopLevel: Int by ::topLevelInt
    
    val delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt
}
var MyClass.extDelegated: Int by ::topLevelInt
                
                    class MyClass(var memberInt: Int, let anotherClassInstance: ClassWithDelegate) {
    var delegatedToMember: Int by this::memberInt
    var delegatedToTopLevel: Int by ::topLevelInt
    
    let delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt
}
var MyClass.extDelegated: Int by ::topLevelInt
                  
                  class MyClass {
   var newName: Int = 0
   @Deprecated("Use 'newName' instead", ReplaceWith("newName"))
   var oldName: Int by this::newName
}
​
fun main() {
   val myClass = MyClass()
   // Notification: 'oldName: Int' is deprecated.
   // Use 'newName' instead
   myClass.oldName = 42
   println(myClass.newName) // 42
}
                
                    class MyClass {
   var newName: Int = 0
   @Deprecated("Use 'newName' instead", ReplaceWith("newName"))
   var oldName: Int by this::newName
}
​
func main() {
   let myClass = MyClass()
   // Notification: 'oldName: Int' is deprecated.
   // Use 'newName' instead
   myClass.oldName = 42
   print(myClass.newName) // 42
}
                  

Storing properties in a map

                  class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int     by map
}
                
                    class User(let map: Map<String, Any?>) {
    let name: String by map
    let age: Int     by map
}
                  
                  val user = User(mapOf(
    "name" to "John Doe",
    "age"  to 25
))
                
                    let user = User(mapOf(
    "name" to "John Doe",
    "age"  to 25
))
                  
                  println(user.name) // Prints "John Doe"
println(user.age)  // Prints 25
                
                    print(user.name) // Prints "John Doe"
print(user.age)  // Prints 25
                  
                  class MutableUser(val map: MutableMap<String, Any?>) {
    var name: String by map
    var age: Int     by map
}
                
                    class MutableUser(let map: MutableMap<String, Any?>) {
    var name: String by map
    var age: Int     by map
}
                  

Local delegated properties

                  fun example(computeFoo: () -> Foo) {
    val memoizedFoo by lazy(computeFoo)
​
    if (someCondition && memoizedFoo.isValid()) {
        memoizedFoo.doSomething()
    }
}
                
                    func example(computeFoo: () -> Foo) {
    let memoizedFoo by lazy(computeFoo)
​
    if (someCondition && memoizedFoo.isValid()) {
        memoizedFoo.doSomething()
    }
}
                  

Property delegate requirements

                  class Resource
​
class Owner {
    val valResource: Resource by ResourceDelegate()
}
​
class ResourceDelegate {
    operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
        return Resource()
    }
}
                
                    class Resource
​
class Owner {
    let valResource: Resource by ResourceDelegate()
}
​
class ResourceDelegate {
    operator func getValue(thisRef: Owner, property: KProperty<*>): Resource {
        return Resource()
    }
}
                  
                  class Resource
​
class Owner {
    var varResource: Resource by ResourceDelegate()
}
​
class ResourceDelegate(private var resource: Resource = Resource()) {
    operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
        return resource
    }
    operator fun setValue(thisRef: Owner, property: KProperty<*>, value: Any?) {
        if (value is Resource) {
            resource = value
        }
    }
}
                
                    class Resource
​
class Owner {
    var varResource: Resource by ResourceDelegate()
}
​
class ResourceDelegate(private var resource: Resource = Resource()) {
    operator func getValue(thisRef: Owner, property: KProperty<*>): Resource {
        return resource
    }
    operator func setValue(thisRef: Owner, property: KProperty<*>, value: Any?) {
        if (value is Resource) {
            resource = value
        }
    }
}
                  
                  fun resourceDelegate(): ReadWriteProperty<Any?, Int> =
    object : ReadWriteProperty<Any?, Int> {
        var curValue = 0 
        override fun getValue(thisRef: Any?, property: KProperty<*>): Int = curValue
        override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
            curValue = value
        }
    }
​
val readOnly: Int by resourceDelegate()  // ReadWriteProperty as val
var readWrite: Int by resourceDelegate()
                
                    func resourceDelegate(): ReadWriteProperty<Any?, Int> =
    object : ReadWriteProperty<Any?, Int> {
        var curValue = 0 
        override func getValue(thisRef: Any?, property: KProperty<*>) -> Int = curValue
        override func setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
            curValue = value
        }
    }
​
let readOnly: Int by resourceDelegate()  // ReadWriteProperty as val
var readWrite: Int by resourceDelegate()
                  

Translation rules

                  class C {
    var prop: Type by MyDelegate()
}
​
// this code is generated by the compiler instead:
class C {
    private val prop$delegate = MyDelegate()
    var prop: Type
        get() = prop$delegate.getValue(this, this::prop)
        set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}
                
                    class C {
    var prop: Type by MyDelegate()
}
​
// this code is generated by the compiler instead:
class C {
    private let prop$delegate = MyDelegate()
    var prop: Type
        get() = prop$delegate.getValue(this, this::prop)
        set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}
                  

Providing a delegate

                  class ResourceDelegate<T> : ReadOnlyProperty<MyUI, T> {
    override fun getValue(thisRef: MyUI, property: KProperty<*>): T { ... }
}
    
class ResourceLoader<T>(id: ResourceID<T>) {
    operator fun provideDelegate(
            thisRef: MyUI,
            prop: KProperty<*>
    ): ReadOnlyProperty<MyUI, T> {
        checkProperty(thisRef, prop.name)
        // create delegate
        return ResourceDelegate()
    }
​
    private fun checkProperty(thisRef: MyUI, name: String) { ... }
}
​
class MyUI {
    fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { ... }
​
    val image by bindResource(ResourceID.image_id)
    val text by bindResource(ResourceID.text_id)
}
                
                    class ResourceDelegate<T> : ReadOnlyProperty<MyUI, T> {
    override func getValue(thisRef: MyUI, property: KProperty<*>): T { ... }
}
    
class ResourceLoader<T>(id: ResourceID<T>) {
    operator func provideDelegate(
            thisRef: MyUI,
            prop: KProperty<*>
    ): ReadOnlyProperty<MyUI, T> {
        checkProperty(thisRef, prop.name)
        // create delegate
        return ResourceDelegate()
    }
​
    private func checkProperty(thisRef: MyUI, name: String) { ... }
}
​
class MyUI {
    func <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { ... }
​
    let image by bindResource(ResourceID.image_id)
    let text by bindResource(ResourceID.text_id)
}
                  
                  // Checking the property name without "provideDelegate" functionality
class MyUI {
    val image by bindResource(ResourceID.image_id, "image")
    val text by bindResource(ResourceID.text_id, "text")
}
​
fun <T> MyUI.bindResource(
        id: ResourceID<T>,
        propertyName: String
): ReadOnlyProperty<MyUI, T> {
   checkProperty(this, propertyName)
   // create delegate
}
                
                    // Checking the property name without "provideDelegate" functionality
class MyUI {
    let image by bindResource(ResourceID.image_id, "image")
    let text by bindResource(ResourceID.text_id, "text")
}
​
func <T> MyUI.bindResource(
        id: ResourceID<T>,
        propertyName: String
): ReadOnlyProperty<MyUI, T> {
   checkProperty(this, propertyName)
   // create delegate
}
                  
                  class C {
    var prop: Type by MyDelegate()
}
​
// this code is generated by the compiler 
// when the 'provideDelegate' function is available:
class C {
    // calling "provideDelegate" to create the additional "delegate" property
    private val prop$delegate = MyDelegate().provideDelegate(this, this::prop)
    var prop: Type
        get() = prop$delegate.getValue(this, this::prop)
        set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}
                
                    class C {
    var prop: Type by MyDelegate()
}
​
// this code is generated by the compiler 
// when the 'provideDelegate' function is available:
class C {
    // calling "provideDelegate" to create the additional "delegate" property
    private let prop$delegate = MyDelegate().provideDelegate(this, this::prop)
    var prop: Type
        get() = prop$delegate.getValue(this, this::prop)
        set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}
                  
                  val provider = PropertyDelegateProvider { thisRef: Any?, property ->
    ReadOnlyProperty<Any?, Int> {_, property -> 42 }
}
​
val delegate: Int by provider
                
                    let provider = PropertyDelegateProvider { thisRef: Any?, property ->
    ReadOnlyProperty<Any?, Int> {_, property -> 42 }
}
​
let delegate: Int by provider