Separate stored data from derived data
A property can store a value, compute one through a getter, or control writes with a setter. field refers to a backing field inside an accessor and prevents accidental recursive access.
class Progress(private val total: Int) {
init { require(total > 0) }
var completed: Int = 0
set(value) {
require(value in 0..total)
field = value
}
val fraction: Double
get() = completed.toDouble() / total
}
fraction is derived each time; it does not require a second value that can fall out of sync. Writing completed = value inside its own setter would recursively call that setter. The custom setter is not a substitute for validating an initializer: initialization does not invoke it in the same way as a later assignment.
Exercise
Set completion to two of eight and expect 0.25. Attempt a value above the total and confirm the earlier value remains. Explain when a costly getter should become an explicit function or cached result.