The person's birthday is immutable and can't change. The age isn't a mutable property -- it depends on what time we're comparing their birthday to. So it should be computed by a function as he himself says.
The val not being immutable problem is more about declaring something like a list as a val (or final in Java), and being free to modify the elements within the collection anyway so long as the reference to the collection isn't reassigned.
kotlin does have immutable versions of collections in its standard library. It's just not a language feature.
They had a "feature poll" at a 1.1 event a while back, where one of the features you could vote for was "true immutability".
Can't find any links now that explain how that would work though. I just remember that it was completely different from C++'s const-correctness (which is what I assumed at first when reading its title).
This was discussed very very early. Basically type system would not allow to declare `var` inside class. It would apply to object graph, so immutable collection could not store mutable objects etc..
Problem is that type system in Java is dynamic at runtime. It is not possible while maintaining interoperability with Java code.
Simple answer here is just don't define custom getters, however I do agree that such functionality shouldn't even be allowed by the language for `val` properties. Instead, if you want to define a custom getter, Kotlin should require that property to be a `var` (or `fun` since they're really functions).
That'd forbid a really common and innocuous use-case, where your custom val-getter is a simple function of other immutable data on the object. I use these all the time; they save on memory, allow lazy-init, and preclude the possibility of them getting out-of-sync with the source data if you later change their dependencies to mutable. (Although that introduces the issue described in the article; I would rather have code that is logically correct but surprising than code that is buggy.)
A useful compromise might be for Kotlin to force 'var' if any of the fields used in the property body is itself a var, or is a function. It has this information already; it displays them in italics in the IDE, so no reason the compiler couldn't propagate that upwards.
will always return the same reference, but the state of the referenced object may have been mutated, which isn't what I'd expect when you say "always immutable, really".
It's subtle, but you're both saying different things. What happens with Kotlin cannot happen with Scala `val`s. Note in Kotlin it may return something entirely different, not just the same reference to a mutable object. It seems that in Kotlin a `val` may get evaluated every time it's called, whereas in Scala it can only be evaluated once.
In Scala it cannot happen that you call a `val` twice and it returns a different object.
'lazy val foo: Int' which is immutable but doesn't execute its right hand side until the first time it called and then stores and returns the value returned by the right hand side everytime.
not that they are different enough to be mentioned
upvoted, but I think you meant "that's NOT true for Scala" (for the reasons you mentioned).
Also, it should be clarified that `val` in Scala gets evaluated only once, which is why it cannot return different things at different times, unlike `def`.
In Scala it's much less of an issue because the culture is immutable-first, and the library ecosystem is established enough that you don't often have to resort to a mutability-oriented Java library. I understand things are similar for Clojure.
I'm really annoyed by val as well, but the standard library is immutable-first so it's never really a problem for things you haven't written yourself. It can probably be a real pain for larger software with lots of invented-here classes, made by former Java devs, though.
At first I thought the same as you, but the problem is actually subtler. It's not about an immutable reference to a mutable object, but actually a reference that gets re-evaluated each time it's invoked, which is something that cannot happen with Scala `val`s!
Not sure if you read the post or not because it's really complaining about the fact that you can define custom getters for `val` fields in Kotlin. There is no real equivalent in Java here since Kotlin overloads class fields such that they represent both functions and variables (they're similar to C# properties).
val field is a shorter way of saying getField, actually, not final field, and that's the point of the article. Kotlin just doesn't have fields in Java sense (though it uses them, of course), for programmer they are properties, AKA getter+setter with trivial getter/setter generated automatically.
Though, you can add an annotation to get field behavior - it's mainly for java compatibility from what I can tell (and it's documented in the java interop section).
I'm not sure if using that annotation also generates the getters/setters though.
The article talks about immutable objects vs read-only objects. Final and Val means read only, the reference is immutable, not the object. For class variables Val and final are almost exactly the same.
val reference is not immutable. Your val can return new reference every time it's called:
val x: String get() = (i++).toString()
And JVM just don't have any notion about immutable objects, so Kotlin, obviously, don't have them either. You can return some ImmutableList and I'll change it using reflection and laugh at you. Immutability in Java is about conventions and trust.
To do this the way Dan expects, you either need to have two parallel type systems (like C++'s const - a bad idea, because you ultimately end up needing to write const and non-const versions of methods) or you only allow expressions of immutable types to be made vals.
Having immutable types as a first-class language concept is a good one, and much simpler to reason about, since it states an invariant that the compiler can check and that most programmers understand as a first-level concept.
The author doesn't seem to be complaining about interior mutability, AFAICT.
Scala makes the case the author is complaining about clearer than Kotlin, by using the 'def' keyword (same as functions/methods) for getters rather than 'val' (the latter can only be used for values). Matching the style of the article, it's:
class Person(val birthDay: DateTime) {
def age: Int = yearsBetween(birthDay, DateTime.now)
}
You can't use 'val' here and so excepting interior mutability, Scala 'val's don't change (and importantly, the reference you get by naming one doesn't ever change).
Rust seems to handle that reasonably well, interior mutability[0] aside mutating an object requires having an &mut to it, which you can only get through a mut binding (or a pre-existing &mut).
Swift also classifies methods between regular (accessible on both var and let binding) and `mutating` (only accessible on let bindings), though I think that also works for value types (structs).
> Swift also classifies methods between regular (accessible on both var and let binding) and `mutating` (only accessible on let bindings), though I think that also works for value types (structs).
Just to clarify the terminology, the `mutating` keyword in Swift is only used with value types (`struct` and `enum`) and is only accessible on `var` bindings (`let` bindings are readonly).
IMO allowing interior mutability by default on `let`-bound reference (`class`) types was a mistake in the language design and the same syntax should've been required there, but I assume Apple wanted to make things clearer for programmers who don't have a C/C++/similar background and so don't yet understand the distinction between [stack-allocated, pass-by-copy] values and references [to heap-allocated, reference-counted objects].
In C++ terms:
struct O {int f;};
template<class T> struct SwiftRef : shared_ptr<T> {
template<class U> SwiftRef(U u) : shared_ptr<T>(new T{u}) {}
operator T() const noexcept {return **this;}
};
O struct_var_binding{4};
const O struct_let_binding{4};
SwiftRef<O> class_var_binding{4};
const SwiftRef<O> class_let_binding{4};
// What it should be, IMO: const SwiftRef<const O> class_let_binding{4};
> IMO allowing interior mutability by default on `let`-bound reference (`class`) types was a mistake in the language design and the same syntax should've been required there, but I assume Apple wanted to make things clearer for programmers who don't have a C/C++/similar background and so don't yet understand the distinction between [stack-allocated, pass-by-copy] values and references [to heap-allocated, reference-counted objects].
They also likely didn't want to make the work of bridging/using Obj-C types (which I believe are all reference types) even harder.
Could you explain why would I need to write two versions of methods? I always liked C++ const-ness, the only drawback that I see is that const-ness should be default and something like `sideeffect` modifier should be applied for non-const functions.
In C++, there need to be e.g. two overloaded versions of the index operator on a vector: one taking a const vector reference returning a const reference to the value, and one taking a non-const vector reference returning a non-const reference to the value.
With only the first one you couldn't modify values of a vector using nice [] syntax. With only the second one you couldn't use the same nice [] syntax on const vectors. So you need both. The implementation can be identical, but the method signature is different. You end up with such duplicate functions all the time for accessor methods.
This is something Swift handles well - computed properties, even if they only have getters, are only allowed to be "var"s, not "let"s (Swift's equivalent to Kotlin's "val").
Looking over the "Learn Kotlin in X minutes" which was posted on HN a few days ago, I was amazed to see how similar Kotlin is to Swift - but this is one difference at least.
More importantly, Swift's structs come close to full immutability. If you declare a struct instance with `let`, the compiler throws an error if you try mutating its properties. You also have to mark functions in the struct as mutating if they modify any property. The only case this isn't true (and why I said comes close) is if you modify a property of a reference type within a struct.
I like to overuse let for signalling mutable content. In other words, I only use const when the variable is read-only and never to be mutated.
Even by that narrower ruleset, nearly all variables end up being const. This way a "let" signals to the reader "watch out, something is going to be mutated here", which IMO is a more useful note to the reader than "watch out, this reference can be changed".
Perhaps I should have stated "const vs let", with "let" being JavaScript's modern, scoped version of "var"... but even so, I think this is just the sort of confusion that the author is trying to clear up.
"let" in JS doesn't mean "mutable" just as "var" in Kotlin doesn't either. While one can use them as reminders to the programmer as to the mutability of the underlying object, there is nothing in the language that enforces this, so this is technically, syntactically incorrect.
In both languages, it might make more sense to simply label variables directly with something like `${variable name}_IMMUTABLE`, which gives a clear clue to the programmer that the variable is immutable, but doesn't imply anything that's untrue about the how the language is used.
Because that doesn't do what people want/expect, if you have a key with a value that's not frozen it will still be mutable, which indirectly mutates your object.
Freezing an object doesn't freeze it's children, and thus it's still technically mutable. I think using deep-freeze (https://github.com/substack/deep-freeze) might work.
No, it isn't the same confusion. The article describes a different problem (worse, IMO). Read it again, or read the following comment in this HN thread: https://news.ycombinator.com/item?id=14445829
The val not being immutable problem is more about declaring something like a list as a val (or final in Java), and being free to modify the elements within the collection anyway so long as the reference to the collection isn't reassigned.
kotlin does have immutable versions of collections in its standard library. It's just not a language feature.