Norway


When I first , the difference between val and var seemed simple: val means immutable and var means .

The truth is more nuanced than that: val does not mean immutable, val means read-only. That means that you’re not allowed to explicitly write to a val, but it doesn’t guarantee that they’re immutable1.

Mutable Class Properties

For variables, the distinction between immutable and read-only is a moot point. There’s no way to write a val variable or override how it is retrieved, so it is (for all intents and purposes) immutable.

For class properties, however, the read-only nature of val makes a huge difference.

In the context of properties, val vs. var indicates whether getters/setters exist for the property. A var has both a getter and a setter, whereas a val only has a getter.

In the simple case, the lack of a setter means that val class properties are immutable. However, it is possible to add a custom getter function for any class property, allowing you to return whatever you want each someone accesses the property. For example:

class Person(val birthDay: DateTime) {  
  val age: Int
    get() = yearsBetween(birthDay, DateTime.now())
}

As you can see, there’s no explicit way to set Person.age, but Person.age will change values as the current date changes.

In fact, thinking of Person.age as a variable at all is a misnomer. It’s actually a getter function that you’re calling that may change values over invocations.

Consequences

I was personally horrified when I learned about mutable in Kotlin. I felt betrayed – val vs. var marking as immutable vs. mutable was one of the first cool features from Kotlin I learned!

As far as I can tell, there are two arguments to be made for customizable getters for val class properties:

  1. Class properties are just a shorthand for getters/setters, and customizing getters is generally thought of as okay.
  2. Customizable getters enable delegated properties.

Delegated properties are a compelling use case and I will continue to use them. However, I find it much easier to reason about code when val implies an immutable reference. Immutability makes code (especially concurrent code) much easier to work with.

As such, I have chosen not to use custom getters for val class properties. If a read-only class property changes value over time, I instead replace that property with a normal function:

class Person(val birthDay: DateTime) {  
  fun age(): Int = yearsBetween(birthDay, DateTime.now())
}

This preference is what the Kotlin coding conventions recommends anyways. It states that you should prefer a property over a function only when the underlying algorithm:

  • does not throw
  • has a O(1) complexity
  • is cheap to calculate (or caсhed on the first run)
  • returns the same result over invocations

Overriding the getter and changing the reference violates the last condition, so avoid doing it!




Source link

LEAVE A REPLY

Please enter your comment!
Please enter your name here