Reputation: 179
What is the purpose of Kotlin's implicit calling of getter/setter functions for properties when you try to access them? Isn't the point of getter and setters already that you can easily call them if you intend to use them? Kotlin's version basically just introduces an additional complexity with the 'field' identifier and introduces weirdness like the following, where an object may not behave like its interface intended:
interface Counter {
var count: Int
fun increment() {
count = count + 1
}
}
class WeirdCounter: Counter {
override var count: Int = 0
get() = field
set(value) {println("ignore the value")}
}
Just trying to understand the intent behind this.
Upvotes: 1
Views: 866
Reputation: 18547
The way Kotlin implements properties using getters and setters is basically what's common practice — and best practice — in many other languages.
‘Bare’ fields, as in Java, are simple, clear, and easy to use; but bare fields have problems:
They expose an implementation detail (the field, and especially its type), preventing it from being changed in future.
They don't allow the class to control its own state.
Of course, these aren't a problem for simple value classes. But for more complex classes, they can be a real problem.
For example, you may want to change the way a class stores its state (e.g. replacing a long
with a BigDecimal
), but if that class is part of a popular library's public interface then thousands of users would get pretty annoyed.
Or suppose it would be really convenient if you could ensure that a String property was always stored in lower-case without leading or trailing whitespace. But with a ‘bare’ property there's no way to enforce that.
So the usual pattern is to have a field that's private, and only accessible from within the class itself (which you control); and provide accessor methods.
That gives you full control. You can change the internal representation, as long as you update the accessor methods to convert to/from the new form as needed. And your setter can do any normalisation, formatting, or whatever to enforce any restrictions on the state.
However, in languages like Java, that's more awkward and long-winded than a simple field: accessor methods turn a one-line field into seven lines (excluding blank lines, and excluding doc comments, so that's probably more like turning 3 lines into 21). And while calling a getter method is only a few characters longer (with get
and ()
) than referencing a field, calling a setter is a lot less intuitive than a simple assignment.
The result is that either developers do the right thing and fill their classes with boilerplate (with all the implications for maintainability and risk of error), or they don't bother and risk the problems above.
Kotlin, though, gives the best of both worlds: a simple property looks just like a field, both when defining and when accessing it. So you get the lean, concise, clear code. But it's implemented with a private backing field (if needed) and accessor method(s)s, so you get all the advantages of those too. And if you ever need to add validation or change the representation or log all access or whatever, you have the option of replacing the default accessors with your own implementations.
Your WeirdCounter
example is odd, but not as scary (or as likely) as you might think. In an object-oriented language, a class is master of its own state, and other classes generally don't and shouldn't know about its internals. (That way, they're insulated from changes to those internals.) If a class needs to do something counter-intuitive in a setter, that's only a concern if it breaks the class's contract — but that would be a bug, and should become obvious in tests, if not elsewhere.
In practice, the ability for classes to control access to their state is more important than the risk of a class using that to do something stupid or malicious (that would be fairly easy to spot).
Upvotes: 5