Val by Delegate (Bug or feature?)

Hello,

consider the following:

class GetMe {
    var a = 1
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
        return ++a
    }
}

private val getMe = GetMe()
private val testMe: Int by getMe

@Test
fun `I'm a playground, not a test`() {
    println(testMe)
    println(testMe)
    println(testMe)
}

We can change testMe values although it is declared as val. Shouldn’t Kotlin compiler take care of this case and not allow this kind of delegate?

No. val means readonly. Not unchangeable.

Another way to say it is: Val does not mean immutable
Here’s an example without delegates:

class Person {
  var _age = 1
  val age: Int get() = _age++
}

fun main() {
  val bob = Person()
  println(bob.age)
  println(bob.age)
  println(bob.age)
}
1 Like

Using Java terms, val merely means a getter API method. There is nothing in Java or Kotlin that hints a getter method always returns the same value.

1 Like

This looks like a workaround to me but val is immutable given
val a = 10
a = 20
throws an error in the snippet given we are age does not practically exist as it is fetched from an already declared value i.e _age which is the one being fetched.

Yes, in this example val a is an immutable value. However that does not mean that val itself declares makes a value immutable. As pointed out by Jonathan Haas and arocnies val makes a value readonly. In your example there is no way of changing this readonly value, therefor it’s immutable.


Also there is a small difference between properties and values inside of functions. You could very well argue that a simple value inside of a function is immutable (as long as you don’t declare it using a delegate or custom getter), but that’s not really what the OP was asking about.

Kotlin’s abstraction in general only allows for the distinction between readonly and mutable. Kotlin itself does not have a concept of immutable. This is also the case for List vs MutableList, where many people confuse the first for being immutable, which is wrong.

1 Like

That’s immutable mainly because Int is immutable. You can’t write 10.value = 20 or something like that.

Had you written

var a = 10
a = 20

you wouldn’t have mutated the original Int value, it would be like writing

var a = Int(10)
a = Int(20)

and not like

var a = Int(10)
a.value = 20

so you just assign a new object/value.