natzelo
natzelo

Reputation: 66

Understanding the impact of var and val with respect to getters and setters of a property

Let's say I have a Kotlin class Dog with two properties weight and weightInKgs

class Dog(val weight: Double) {  
    // property without initializing works. Why?
    val weightinKgs: Double
    get() = weight/ 2.2;
}

The above code runs without errors. I know that every property in Kotlin must be initialized so why does defining a getter without initializing the property work? Secondly, when val is changed to var for weightInKgs, it produces an error asking for initialization. How does changing it to var break the code?

class Dog(val weight: Double) {
    // well its doesn't work now. 
    var weightinKgs: Double
        get() = weight/ 2.2;
}

Upvotes: 0

Views: 39

Answers (2)

Tenfour04
Tenfour04

Reputation: 93551

Every property with a backing field must be initialized. A property has a backing field if any of the following is true:

  • You initialize the backing field at the declaration site using =.
  • It has a custom getter or setter that references field.
  • It uses the implicit getter or setter, which implicitly uses field.

Otherwise, it does not have a backing field.

If there is no backing field used by the getter and/or setter, there is no need to initialize one. Your first code block has a custom getter that doesn't use field.

In your second code block, you have a var and it's using the implicit setter, which uses the backing field, so the backing field must be initialized.

Upvotes: 3

cactustictacs
cactustictacs

Reputation: 19524

If it's not obvious, get() is a function that calculates a value (weight / 2.2) every time you call it. It's basically the equivalent to this

fun getWeightInKgs(): Double {
    return weight / 2.2
}

So that's why it doesn't have a backing field, it's not actually storing a value. But Kotlin presents these kinds of getX() functions (and set, is etc) as properties, and encourages you to use property access syntax, so dog.weightInKgs instead of dog.getWeightInKgs(). Kinda hiding the specific implementation details

If you didn't want to calculate the weight every time, and just wanted to do it once, then you'd just do

val weightInKgs = weight / 2.2

and then it would have a backing field, because that value has to be stored somewhere. You could also have a getter function that refers to a private val or var and returns the value of that, instead of giving the property itself a backing field, but if you ever need to do that kind of thing you'll probably understand why you would! That's usually for when your getter and/or setter is doing something a bit more complicated than just hiding or validating an internal data value

Upvotes: 0

Related Questions