Custom Accessors

Sometimes, you will see a get() or perhaps a set() associated with a property. Those are custom accessors, replacing the stock ones that Kotlin would generate for you.

Defining Custom Accessors

Each Kotlin property is made up of a field, a getter function, and a setter function. By default, the getter and setter are code-generated for you, but you can override those with custom implementations if desired.

For example, here is a property with a custom getter function:

val stuff = mapOf("something" to "This is the 'something' value")
val something: String?
  get() = stuff["something"]

fun main() {
  println(something)
}

The custom getter goes on the line after the property declaration. It is declared as a get() function and needs to return an object matching the property’s data type. Otherwise, though, the actual function implementation is up to you. In this case, we declare that the something value really comes from the stuff Map, rather than from the field that ordinarily would be the value of something.

Not surprisingly, you can override the setter function too. That requires a var property, as a val property has no setter. The setter appears after the property, alongside the getter (if there is one). The setter is a set(value) function, where value is the value that is being set. So in this example, we turn around and put that value into the stuff using our something key:

val stuff = mutableMapOf<String, String?>("something" to "This is the 'something' value")
var something: String?
  get() = stuff["something"]
  set(value) { stuff["something"] = value }

fun main() {
  something = "This is different"
  println(something)
}

Note that users of the property are not affected by these changes. You use the same syntax for working with the property as before.

Referencing the Field

If you declare a normal simple property, Kotlin will create the corresponding field into which the data gets stored. The generated getter returns the value of the field, while the setter replaces the value in the field.

If you declare custom accessors, by default Kotlin will not generate a corresponding field… unless you choose to reference it from the custom accessor functions via the field name. Then, Kotlin creates that field and field serves as a reference to it. If your accessors reference field, though, your property needs an initializer, to supply the initial value for field.

So, this is basically what the default Kotlin code generation would look like if you did it manually:

var something: String = "This is the 'something' value"
  get() = field
  set(value) { field = value }

fun main() {
  something = "This is different"
  println(something)
}

Inline Getters

For a val property, if your custom getter clearly indicates the data type of the property, you can skip putting the data type on the property itself. Instead, put the custom getter function immediately after the property name:

val stuff = mapOf("something" to "This is the 'something' value")
val something get() = stuff["something"]

fun main() {
  println(something)
}

Configuration Without Customization

Sometimes, you do not need to fully customize the accessor, but simply configure it slightly.

For example, you might have a var property in a class, because you need to assign a new value to it after initialization. However, modifying that property should be limited to instances of the class itself, whereas reading that property might be available to all classes. In other words, you want a semi-public property: public getter and private setter.

That is just a matter of having a private set declaration, without a function body:

class Whatever {
  var something: String = "This is the 'something' value"
      private set

  // TODO
}

Instances of Whatever can modify the something property, while everything else is limited to reading that property.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.