Are public attributes rather than private attributes with get/set methods common practice?

In fact, the only necessary part is the getter method.

If you define a simple property, e.g.:

val myField = 1

…then the compiler will generate a backing field which is private (unless overridden by an annotation), and a getter method of the relevant visibility (in this case public). If it were a var, it would have a setter method too.

But you can define your own accessor method(s) instead, e.g.:

val myField = 1
    get() = if (overridden) 0 else field

Within the accessor, field refers to the backing field.

You could even write accessor(s) that don’t refer to the backing field, e.g.:

val myField: Int
    get() = someOtherField * 2

In this case, the compiler doesn’t generate a backing field at all; just the accessor method(s).

That’s what allows you to write extension properties. You can’t add state to an existing class; but you can effectively add behaviour (as in extension functions), and this can also apply to properties, as long as there’s no backing field. For example:

val Int.reciprocal
    get() = 1.0f / this

This defines an extension property to the Int type. So wherever that’s in scope, you can type e.g. println(1.reciprocal) just as if Ints had a new field.

So a Kotlin property is implemented in the traditional Java way: it always has a getter method, and may also have a setter method (if it’s a var) and/or a backing field (if that’s needed) — giving you flexibility and interoperability. But at the language level, it looks like a field, with simple syntax and readability. Best of both worlds!

3 Likes