Make your code beautiful with Kotlin Property Delegates
Tags: kotlin
Published: 2020-04-24 10:05:47

My colleague [Andreas Feldschmid](https://twitter.com/icyerasor) and I are about to prepare advanced Kotlin topics for the second day of a two-day Kotlin training. It's pretty amazing that we are now Kotlin trainers at our company [iteratec](https://iteratec.com) - and I'll write another blogpost about how that came to be in the upcoming weeks. By the way: if there is anything that **you** would love to learn in an advanced Kotlin training: please leave a comment below or write me [on Twitter](https://twitter.com/mreichelt)! 📩

In order to select topics for this training, we were talking about lots of Kotlin features and libraries. And one topic that came up were **Delegated Properties**. He heard about them, but didn't use them yet. So I quickly opened IntelliJ and showed him this example.

## Small recap on properties

This is pretty standard: In Kotlin, we can define mutable properties with `var` and values with `val`. Let's see some code:

```kotlin
class Preferences {
    var username : String = ""
}
```

Here, we have a property `username`. And each mutable property has a getter and a setter, which you can override. By the way, if you don't know the syntax by memory, you can simply type `Alt + Enter` on `username` and get the quick action for that:

![Type Alt + Enter on a property in IntelliJ to add getter and setter methods](https://dev-to-uploads.s3.amazonaws.com/i/dalk955w0e3kklztdcwi.png)

There's more to read about that in the [Kotlin docs on properties](https://kotlinlang.org/docs/reference/properties.html). But instead of implementing properties yourself, you can instead create *delegated properties*, where the getter and setter are provided someplace else.

## Awesome code with delegated properties

A delegated property, as [described in the Kotlin docs](https://kotlinlang.org/docs/reference/delegated-properties.html) is simply defined by using the `by` keyword and a delegate instance:

```kotlin
class Preferences {
    var username : String by Delegate()
}
```

This can be any class that implements the operator functions `getValue` and `setValue`. You can copy those from the documentation - but you can simply let IntelliJ create that class for you. And there are interfaces `ReadWriteProperty` and `ReadOnlyProperty` available which can help you with the syntax as well.

As an example, we'll create a `FileDelegate` that reads and writes text to a file, and takes a file name as parameter:

```kotlin
class Preferences {
    var username: String by FileDelegate("username.txt")
}

class FileDelegate(val fileName: String) : ReadWriteProperty<Preferences, String> {

    override fun getValue(thisRef: Preferences, property: KProperty<*>): String {
        val file = File(fileName)
        return if (file.exists()) file.readText() else ""
    }

    override fun setValue(thisRef: Preferences, property: KProperty<*>, value: String) {
        File(fileName).writeText(value)
    }

}
```

Now we can access the content of the file `username.txt` by accessing the property! Isn't that cool?

```kotlin
fun main() {
    val preferences = Preferences()
    println(preferences.username)
    preferences.username = "Marc"
    println(preferences.username)
}
```

Even better, we now can reuse the same functionality with multiple properties:

```kotlin
class Preferences {
    var username: String by FileDelegate("username.txt")
    var accessToken: String by FileDelegate("accessToken.txt")
    var favoriteFood: String by FileDelegate("favoriteFood.txt")
}
```

Wouldn't it be nice if we could even generate the filename according to the name of the property? Easy as pie, because each `KProperty` has a `property.name` we can use:

```kotlin
class FileDelegate : ReadWriteProperty<Preferences, String> {

    override fun getValue(thisRef: Preferences, property: KProperty<*>): String {
        val file = File(property.name + ".txt")
        return if (file.exists()) file.readText() else ""
    }

    override fun setValue(thisRef: Preferences, property: KProperty<*>, value: String) {
        File(property.name + ".txt").writeText(value)
    }

}
```

While only a small change, this makes the code even more readable. Of course, this comes at a cost we should be aware of: If someone refactors a property name, the filename will change, too. If we are willing to accept this, the code will read like this:

```kotlin
class Preferences {
    var username: String by FileDelegate()
    var accessToken: String by FileDelegate()
    var favoriteFood: String by FileDelegate()
}
```

And in addition, because we extend from `ReadWriteProperty<Preferences, String>`, we can let type inference automatically get the `String` return type:

```kotlin
class Preferences {
    var username by FileDelegate()
    var accessToken by FileDelegate()
    var favoriteFood by FileDelegate()
}
```

Let's say that `favoriteFood.txt` is generated by a different program, and we only want to read it here. We can just change `var` to `val`, which effectively hides the setter:

```kotlin
   val favoriteFood by FileDelegate()
```

I think this can come in pretty handy, and delegated properties can make your Kotlin projects nicer to read. Some things you could use delegated properties for:

- Reading/writing things from disk
- Caching values as well (instead of reading them again every time)
- Reading/writing shared preferences in Android (see [this great blog post](https://medium.com/@krzychukosobudzki/sharedpreferences-and-delegated-properties-in-kotlin-5437feeb254d) on how to do that)
- Getting something from the network (although you'll have to call `runBlocking` if you use coroutines, as this mechanism currently does not support suspending coroutines - at least not that I know of)
- Do logging

## Wait, there's more!

The [Kotlin documentation on delegated properties](https://kotlinlang.org/docs/reference/delegated-properties.html) contains more knowledge. For example, I already knew about the `lazy` delegate from Kotlin's stdlib, which can be used to get and store the result of some expensive operation:

```kotlin
val lazyValue: Int by lazy {
    calculateAnswer() // takes 7.5 million years to print 42
}
```

What I didn't know was that you can define the thread safety mode (as lazy is synchronized by default, which can add more overhead than you would expect):

```kotlin
val lazyValue: Int by lazy(mode = LazyThreadSafetyMode.NONE) {
    calculateAnswer() // takes 7.5 million years to print 42
}
```

Another useful thing I didn't know yet was that you can delegate to a map, like so for an immutable map as stated by the Kotlin docs:

```kotlin
class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int     by map
}
```

Have an awesome Kotlin! 🎉

If you liked this post, please give it a ❤️, click the `+FOLLOW` button below and follow me on [Twitter](https://twitter.com/mreichelt)! This will help me stay motivated to create many more of these posts! 😊

*Cover photo by [Anton Sulsky](https://unsplash.com/@antonsulsky) on [Unsplash](https://unsplash.com/photos/YcfCXxo7rpc)*.