The Programmers Guide To Kotlin - Delegated Properties
Written by Mike James   
Monday, 17 December 2018
Article Index
The Programmers Guide To Kotlin - Delegated Properties
Backing Properties

For example, if we change the delegate so that a backing property is used to implement the functioning of a standard property:

class myDelegate{
  private var backing:Int=0
  operator fun getValue(thisRef:Any,
                property:KProperty<*>):Int{
     return backing
  }
  operator fun setValue(thisRef:Any,
                property:KProperty<*>,value:Int) {
    backing=value
  } }

then you can see that each instance of myClass gets it own instance of myDelegate:

val myObject1=myClass()
val myObject2=myClass()
myObject1.myProperty=1
myObject2.myProperty=2
println(myObject1.myProperty)
println(myObject2.myProperty)

The final print statements print 1 and 2 respectively, showing that the instances don't share the property.

You can pass data including lambdas.

One of the best examples of delegation is the Observable which is one of the three standard delegated properties that Kotlin provides – Lazy and Map being the other two.

The observable delegate accepts two parameters. The first is the initial value of the delegated property and the second is a function to be executed whenever the property changes. This function has the signature prop, old, new which give the property being changed, and its old and new values.

For example:

class myClass {
    var name: String by Delegates.observable("<no name>") {
        prop, old, new -> println(new)
    }
}

 

To make this work you have to import the Delegates package:

import kotlin.properties.Delegates

The delegated property is used in the same way as any other, but with the side effect that it prints the new value:

val myObject=myClass()
myObject.name="Mickey"
myObject.name="Minnie"

You will see Mickey and Minnie printed.

Taking the customization of the delegate object even further you can define your own provideDelegate operator. When you create an instance of a class that uses a delegate property then the system automatically creates an instance of the delegate class for you. If you need to, you can do the job yourself by defining the provideDelegate operator as a member or extension function of the delegate class. The provideDelegate is called to create the instance of the delegate class. It receives the same parameters as the get function i.e. thisRef and property, and it has to return an instance of the delegate.

For example to add the provideDelegate operator to our trivial example from earlier:

class myDelegate {
  operator fun provideDelegate(thisRef: MyClass,
                    prop: KProperty<*>): myDelegate {
        println("creating delegate")
        return myDelegate()
    }

 private var backing: Int = 0
  operator fun getValue(thisRef: Any,
                     property: KProperty<*>): Int {
        return backing
    }
  operator fun setValue(thisRef: Any,
                     property: KProperty<*>, value: Int) {
        backing = value
    }
}

Now when we create an instance you will see “creating delegate" printed: 

class MyClass {
    var myProperty: Int by myDelegate()
}
fun main(args: Array<String>) {
    val myObject = MyClass()
    myObject.myProperty = 1
    println(myObject.myProperty)
}

Of course, in practice the provideDelegate operator can do whatever it needs to check the validity of the delegation and to build a custom object to do the job.

You don’t need to know how delegate properties work, but it isn't complicated. When you declare a delegate property the system creates a hidden property with the name propertyname$delegate, which is a reference to an instance of the delegate class this:

private val propertyname$delegate=MyDelegate()

The generated get and set for the property simply hands off to the instance of the delegate class, e.g:

get()=propertyname$delegate.getValue(this,this::propertyname) set(value:type)=propertyname$delegate.getValue(this, this::propertyname,value)

Once you have seen a delegate property in action you should be able to generalize and take the idea in whatever direction you need it to go.

Summary

Italics indicate chapter topics not in this extract

 

  • Kotlin doesn’t provide structs or any value alternative to classes, but it does provide a data class which has data properties and a set of methods to work with them.

  • Equality is a difficult thing to define in an object-oriented world. There are two basic equality operators == for equality of reference and === for structural or content equality.

  • If you want equality to be correctly interpreted for your custom classes you need to implement your own equals method. This can either perform a shallow or a deep comparison.

  • Arrays have a referential definition of equals, but you can also use contentEquals for a shallow structural equals and contentDeepEquals for a deep structural equals.

  • Data classes, List, Map and Set have a generated shallow equals.

  • Enums allow you to construct ordinal data representations that map names to integers. An enum behaves like a static class that has properties that are instances of the same type.

  • An enum can have properties and methods but these are shared between all instances of the type.

  • Sealed classes provide an alternative to enum but you have to do more work to implement similar behavior. They work like a set of derived classes that form a known set. The compiler will check that you have included them all in a when expression.

  • Delegation is an alternative to inheritance and you can automatically delegate property implementation to a specific object that implements a delegated interface.

  • Destructuring is a simple mechanism for unpacking the data contained in a structure into individual variables.

  • The spread operator * allows you to pass an array to a vararg parameter.

 

This article is an extract from: 

Programmer's Guide To Kotlin

Now Available as a Print Book

cover

You can buy it from: Amazon

Contents

Some Chapters Already Available On The Web

  1. What makes Kotlin Special (Book Only)
  2. The Basics: Variables, Primitive Types and Functions
  3. Control
  4. Strings and Arrays
  5. The Class & The Object
  6. Inheritance
  7. The Type Hierarchy 
            Extract  Type and its problems
            Extract  Smart Casts
  8. Generics
            Extract Basic Generics
            Extract Covariance & Contravariance
  9. Collections, Iterators, Sequences & Ranges
            Extract     Collections
            Extract Iterators & Sequences
  10. Advanced functions 
  11. Anonymous, Lamdas & Inline Functions
            Extract    Annoymous and Lambda Functions
            ExtractInline Functions
  12. Data classes, enums and destructuring
            Extract  Data Classes
            Extract      Enums & Sealed Classes 
            Extract 
         Delegated Properties 
            Extract      Destructuring  **NEW!**
  13. Exceptions, Annotations & Reflection
            Extract Exceptions
            Extract Annotation & Reflection 
  14. Working with Java
            Extract Using Swing  

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on, Twitter, Facebook or Linkedin.

Banner


Learn About Serverless with The Linux Foundation on edX
11/09/2020

A new free training course that explains serverless computing and provides first-hand experience in building and deploying code directly to a Kubernetes cluster has just launched on the edX platf [ ... ]



Did You Know Today Is Programmer Day?
12/09/2020

As last year Programmer's Day was September 13th, I imagined that tomorrow would be our special day. I was wrong. Because of the way it is calculated, for 2020, Programmer Day falls on September 12th. [ ... ]


More News

graphics

 



 

Comments




or email your comment to: comments@i-programmer.info

<ASIN:1871962536>



Last Updated ( Saturday, 26 January 2019 )