rednifre
04/14/2025, 11:24 AMinterface FooInterface {
val x: X
}
I introduced a bug, stemming from me only reading x once, because I thought “val means immutable”. The bug fix was to read it multiple times, since it changes.
How does it change? Well, in interfaces, val
apparently only means “no public setter”, it does not mean “immutable”. The implementation looks something like this:
class Foo: FooInterface {
override val x: X
get() = something.getX()
}
Now, my gut reaction to this was “This is awful, ‘val’ should mean ‘immutable’, the interface should change from a field to a getter function to make it more clear.“. However, val
in interfaces meaning “no public setter” and not meaning “immutable” is how the language actually works. So should I rewrite code so that by convention, “val” means “immutable”, or would that just bite me later? Would you change the interface/implementation?Youssef Shoaib [MOD]
04/14/2025, 11:35 AMval
just means "has a getter" and that's all. In fact, you can override a val
property with a var
just fine.
Note that, even if the implementation used a field, X
itself could be mutable in some way. What you want is some deep immutability, which is a complicated language addition.
I wouldn't change the interface at all personally. I might instead add a doc-comment to say "x should return the same value always" or something.rednifre
04/14/2025, 11:51 AMYoussef Shoaib [MOD]
04/14/2025, 11:58 AM@Immutable
applies to types, and signifies that all their properties are themselves immmutable (with the base case being primitives). Wanting something like that is normal, it just is likely complicated to bring into the language (e.g. you can't trust List
, or most interfaces really).
In your case, val
is perfectly reasonable to use. I guess you could also change it to a fun
instead to hammer home that it really should be called to guarantee you're up to date. However, I'd recommend using val
here, since `val`s are generally "idempotent", and that seems to be the case with your property.rednifre
04/14/2025, 12:08 PMI guess you could also change it to aThis sounds like a contradiction. In my case it’s mostly idempotent, as in if you call it 10 times in a row, it will probably return the same X every time, but the point is that it is NOT idempotent and I introduced a bug by only calling it once. I was thinking “`val` if idempotent,instead to hammer home that it really should be called to guarantee you’re up to date. However, I’d recommend usingfun
here, since `val`s are generally “idempotent”, and that seems to be the case with your property.val
fun
if you should call it every time to get the up to date value”, but that would just be a convention.
What do you think about val nextRandomInt
? Is that fine, because that’s how the language works, or should there be some style guidelines against it, in your opinion? Are there any official recommendations for vals vs funs? The way I understand it, they are completely interchangeable (functionally), so maybe the distinction would be purely by convention?Youssef Shoaib [MOD]
04/14/2025, 12:13 PMval
should only have read-like side effects, and so if the source hasn't changed, calling it multiple times should result in the same value. If you then call other functions afterwards, then it's on you to ensure that those functions don't change the source.
val nextRandomInt
I think I'd be completely against because calling it has a side effect that permanently changes something else.rednifre
04/14/2025, 12:15 PMrednifre
04/14/2025, 12:16 PMval nextRandomInt
, because it would supposedly change the internal state of a random number generator somewhere? What do you think about val currentTimeInMilliseconds
?Youssef Shoaib [MOD]
04/14/2025, 12:20 PMcurrentTimeInMilliseconds
I'd be fine with. Calling it repeatedly does nothing of value. Calling it, and then calling some function, may render it out of date.
By "read-like side effects", I basically mean that, if the value of a property call is ignored for some reason, then removing the call shouldn't change the behaviour of code.
There are exceptions here of course for DSLs and suchrednifre
04/14/2025, 12:27 PMephemient
04/14/2025, 12:28 PM