Home > database >  Kotlin explicit vs implicit get() and set()
Kotlin explicit vs implicit get() and set()

Time:06-20

What are the reason why we use or explicitly use get() and set() in Kotlin? I have a model that is throwing an error when I remove explicit get() in its variable declaration.

data class SampleDomain(
    val publishTime: String = ""
) {

    // Removing get() here, publishTime becomes empty
    val formattedDate: String
        get() = LocalDate.parse(publishTime, DateTimeFormatter.ISO_OFFSET_DATE_TIME).format(
            DateTimeFormatter.ofPattern("MMM. dd, yyyy")
        )

}

CodePudding user response:

As broot says, adding get() changes the meaning very significantly.

Without the get(), you're declaring a property with an initial value. For example:

class SomeClass {
    var prop = initialisingFunction()
}

That's roughly equivalent to:

class SomeClass {
    var prop: Int

    init {
        prop = initialisingFunction()
    }
}

So initialisingFunction() is called only once, during construction, and the class stores its value in a backing field after that. If the property is a var, as here, then the value can be changed after that.


But with the get(), you're declaring a property with a custom getter:

class SomeClass {
    val prop
        get() = initialisingFunction()
}

That's even more roughly equivalent to:

class SomeClass {
    fun getProp() = initialisingFunction()
}

Here, there's no backing field to store the property; every time you get its value, it will call initialisingFunction() and hand you that value directly.

If the property is a var, then you'll also need a custom setter. (Otherwise, the default one would cause a backing field to be created, which it would set, but whose value you'd never see…)


Which version to use will depend on your needs. If the property needs to change in line with something external, then a custom getter is probably needed. It can also be a slightly memory saving if you need to return a value that's the same for all instance of the class. But if calculating the value is expensive, and/or if it's different for each instance, especially if it needs to be mutable, then you'll probably need a property with an initialiser.

CodePudding user response:

get() and set() is how we define getters and setters in Kotlin. So simply answering why do we use them is because they are required to define a getter/setter.

If you mean the difference between the following definitions:

val formattedDate: String = acquireDate()
val formattedDate: String get() = acquireDate()

Then get() is not here just to be more explicit. These two code fragments do much different things. The first acquires the date during the object initialization, stores it inside a field and the getter returns this stored value. The second defines a custom getter, but the value is not stored anywhere - the date is acquired again and again every time the getter is invoked.

See the documentation for more info: https://kotlinlang.org/docs/properties.html#getters-and-setters

CodePudding user response:

  1. get()

You can define custom accessors for a property. If you define a custom getter, it will be called every time you access the property (this way you can implement a computed property). Here's an example of a custom getter:

class Recangle(
    var width: Int = 10,
    var height: Int = 20
) {
    val area: Int get() = width * height
    
    init {
        println("old area: $area") // 10 * 20 = 200

        width = 20
        println("new area: $area") // 20 * 20 = 400
    }
}

So with custom getter, every time we call area, width * height will be calculated again, let's see what will happen without custom getter:

class Recangle(
    var width: Int = 10,
    var height: Int = 20
) {
    val area: Int = width * height // 10 * 20 = 200
    
    init {
        println("old area: $area") // 200

        width = 20
        println("new area: $area") // 200
    }
}

Without a custom getter we will get the same result every time we call area, even if the width and the height are changed, so the area we be calculated only the first time and stay the same.

  1. set()

If you define a custom setter, it will be called every time you assign a value to the property, except its initialization. A custom setter looks like this:

class Recangle() {
    var area: Int = 0
        set(value) {
            val areaValue = value / 1000 // make custom operations
            updateArea(areaValue) // use value in other functions
            field = value // update the field value
        }
        
    fun updateArea(area: Int) {}
}

Also you can make setter private:

var area: Int = 100
    private set // the setter is private and has the default implementation
  • Related