Why I need to getter/setter?

What is the difference between:

var number:Int = 10

and

var number:Int = 10
get() = field
set(value){
value = field
}

I can not see any difference on output. May be I don’t know what is going on background? When I must use?

That’s correct there should be no difference in output. The getter and setter you defined do the same thing as the default getter and setter.

To better understand properties, let’s consider Java:
Java does not have properties with getters and setters. Instead, every field is just a field. This means if you expose a field you lose control over it–someone can use it however they want and you can’t change the behavior since it’s just a field.

This is the reason you always create methods in Java named “getNumber()” and “setNumber()” and never expose the field directly. Kotlin, and other languages before it, recognized this is the default and built-in getters and setters to all properties. In Kotlin, you do not have to specify any getters or setters if you don’t use them.

1 Like

Thanks. By the way I didn’t understand that field. What does it mean in properties? Why we assign to get()? It seems like temporary variable.

Kotlin’s properties are (most of the time) backed by a backing field. You can think of it like the actual place where the property is stored. The property is just a facade for interacting with that field, with get being the function called when retrieving the backing field and set called when trying to store a new value into the field.

1 Like

Field = A value, variable, raw value holding thing.

Property = An interface that appears similar to a field but doesn’t necessarily hold a value or allow raw access.

Java field example:

class Foo {
   String bar = "Hello World";
}

Java property example:

class Foo {
    // This is the "backing field" that holds the data. It's totally optional as we could support saving the value of our 'bar' property in some other way--that would mean we had some other way of backing (or supporting) the `bar` proptery.
    private String savedValueOfBar = null;

    void setBar(String value) {
        savedValueOfBar = value;
    }

    String getBar(String value) {
        return savedValueOfBar;
    }
}
2 Likes

As @arocnies well described it, you expose the field to other users and after a while you realize that the raw number value should be converted before accessing, you can’t insert this conversion without a semver break anymore. With getters, this can be adapted silently.

On the flip side, getter/setters are controversial because let them doing more than just setting and getting the field isn’t adequately represented by the corresponding method name.
Changing the fieldname also requires mostly to rename getters/setters (imagine reflection counting on it) likewise causing a semver change.

Changing how to get something silently doesn’t cause a compile error but may cause a semantic error at runtime or even better leads to an unexpected result.
So in return, an explicit semver change/break might be a better solution.

1 Like

BTW, your code for setting the value is backwards. It should be
field = value

field” is the name of the property’s backing field. You should assign the parameter value to the backing field.

1 Like

@softmoore I’ve noticed. Thanks.

This is a valid concern, but I don’t think it’s particularly controversial — I think it’s fairly widely understood that getters and setters should behave in a way that looks like a simple field access.⠀For example, they generally shouldn’t:

  • Take a significant amount of time/processing.
  • Change the visible state of the object, except (for setters) the field being set (and, possibly, other state directly related to it).
  • Throw exceptions (possibly except, for setters, validation-type exceptions).
  • (For getters) Return a different value if the visible state of the object hasn’t changed.

Of course, the compiler can’t enforce that, but there are many other conventions and contracts it can’t enforce.⠀(There’s nothing stopping you from implementing equals() in a way that breaks its contract, for example; but people don’t — not deliberately, anyway!)

And most of the things you’d want to do in a getter or setter are not likely to be very surprising, e.g.:

  • Caching values.
  • Converting/calculating values.
  • Logging changes.
  • Validating changes.
  • Informing listeners of changes.
  • Lazy loading.

(Of course, the Law Of Leaky Abstractions applies, and there’s almost nothing you could do in an accessor method that couldn’t be detected somehow.⠀But people generally use their common sense, and I can’t recall ever being seriously surprised by a getter or setter method.)

5 Likes

Also, getters are most appropriate for computed (a.k.a., derived) properties. My favorite example is a property named age, which is derived from property named something like dateOfBirth. Property dateOfBirth will have a backing field, but property age should be computed. One should never have a backing field for age.

1 Like