-1

Using getters and setters is a very well known practice in object oriented languages. This is done in order to have a greater control on the variables. To achieve this, we make the variables private in java and hence we need both getters and setters there.

But in kotlin this is not the case. Here even public variables are accessed through getters and setters by default. Though setters can be used to validate an assignment to a variable, getters just return the variable as it is stored (and I think this is it for them). Hence custom getters are not required at all.

I have also seen some wrong usage of this feature where instead of writing a zero argument function, they use a val and do the computation in the getter. This creates an illusion that the thing is just a val but in reality it does not store anything and instead it performs a computation every time.

So is there a real need to have a custom getter?

Sourav Kannantha B
  • 2,860
  • 1
  • 11
  • 35

2 Answers2

2

getters just return the variable as it is stored (and I think this is it for them). Hence custom getters are not required at all.

If that was really the case, why have getters at all in Java? One of the goals of encapsulation is to make sure a change in the class doesn't change it's API. It's the same in Kotlin.

I have also seen some wrong usage of this feature where instead of writing a zero argument function, they use a val and do the computation in the getter. This creates an illusion that the thing is just a val but in reality it does not store anything and instead it performs a computation every time.

This is a perfectly valid use case for a custom getter. In Kotlin, one must not assume that using a property is entirely free of overhead. There are many questions to ask yourself when choosing between a property with a getter or a zero-arg function:

  • Does it describe behavior? Use a function (walk(), build(), etc)
  • Does it describe state? Use a property (firstName, lastIndex, etc)

Additionally, a property getter should not throw an exception, should be either cheap to calculate or cached on first access, and should return the same result for multiple consecutive executions. Here's examples from the standard library:

  • ArrayDeque.first() is a function, it throws if deque is empty.
  • List.lastIndex is a property, it's cheap to calculate.
  • Lazy<T>.value is a property, the value is computed and cached on first access.

Most delegated properties make use of custom getters.

More reading:

Nicolas
  • 6,611
  • 3
  • 29
  • 73
  • Thanks, this was exactly the thing I was hoping for. Whenever I googled about accessors, they always tend to focus on setters and hardly a line on getters. `why have getters at all in Java?` In java, to have a setter, you need a getter(since the variable must be private). But this is not a case in kotlin. So I asked. – Sourav Kannantha B Jan 18 '21 at 17:20
  • Also, sorry, I didn't get how to quote in comments. Hence I had to use code style for that. – Sourav Kannantha B Jan 18 '21 at 17:25
  • You can't quote in comments so that's fine. – Nicolas Jan 18 '21 at 17:49
  • there is no rule, that getter should return same value all the time. If property is read-only, it doesn't imply it cannot somehow change. Common example is `size` property on mutable collections. – K.H. Jan 18 '21 at 17:54
  • @K.H. Of course it can change, I didn't say properties had to be constants. What I meant is that if you call the property 10 times in a row without anything else changing, it's reasonable to expect it to return the same value, as for `size` (ignoring concurrency). But you wouldn't make something like `random` or `increment` a property because it would be unintuitive to have a property that changes the state. – Nicolas Jan 18 '21 at 18:05
  • Another way to put it. A `val` is not necessarily a constant, but your design is convoluted if you make the act of accessing the `val` mutate the object. – Tenfour04 Jan 18 '21 at 18:07
  • _observably_ mutate the object; accessing a lazy property the first time mutates it... – Alexey Romanov Jan 18 '21 at 22:45
0

Just some more info. Other than readability, the possibility of defining a custom getter allows you to evolve a class without changing its public members, even if you started with a simple val with no custom getter.

In a language without properties like Java, if you define a public field:

public class Foo {
    public final int value;

    public Foo(int value) {
        this.value = value;
    }
}

And then later you want to modify the class to add a feature where it returns negated values if you flip a Boolean, there's no way to do it without breaking code that uses the original version of the class. So you should have used getters and setters to begin with.

But in Kotlin, you can't directly expose a backing field like this, so it's impossible to paint yourself in a corner like you could with a public field in Java. If your original class is like this:

class Foo(val value: Int)

You could modify it like this to add the feature and have no impact on code that already uses the class.

class Foo(private val originalValue: Int) {
    var isNegated = false

    val value: Int
        get() = if (isNegated) -originalValue else originalValue
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154