
Mutable vals in Kotlin - ingve
http://blog.danlew.net/2017/05/30/mutable-vals-in-kotlin/
======
gumballhead
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.

------
realharo
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).

~~~
jankotek
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.

------
opmac
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).

~~~
nostrademons
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.

------
AzzieElbab
Same thing with scala or clojure. If the object is mutable setters and other
methods can still mutate it

~~~
sjrd
No that's true for Scala. Scala has, in fact _three_ kinds of "properties":

* `val foo: Int`: always _immutable_ , really. Every access always returns the same value

* `var foo: Int`: mutable

* `def foo: Int`: "getter" of sorts; cannot be written to, but can return different values when called several times

~~~
kod
That's not really accurate either.

val foo: Object

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".

~~~
the_af
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.

------
hota_mazi
> val does not mean immutable

Yes it does. It means immutable reference.

------
lern_too_spel
Kotlin is targeted at Java developers, for whom val is just a shorter way of
saying final <type>.

~~~
vbezhenar
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.

~~~
jorgemf
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.

~~~
vbezhenar
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.

~~~
jorgemf
I said Val means read only, not immutable. I never said java have immutability
(only for primitive values)

------
barrkel
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.

~~~
masklinn
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).

[0] [https://doc.rust-lang.org/book/mutability.html#interior-
vs-e...](https://doc.rust-lang.org/book/mutability.html#interior-vs-exterior-
mutability)

~~~
smitherfield
_> 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};

~~~
masklinn
> 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.

------
epaga
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.

~~~
trevor-e
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.

------
johnhenry
Similar confusion in Java Script regarding const vs var.

~~~
skrebbel
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".

~~~
johnhenry
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.

Further, one can assign these variables using a library like immutable.js
([https://facebook.github.io/immutable-
js/](https://facebook.github.io/immutable-js/)), or Kotlin's immutable
collections
([https://github.com/Kotlin/kotlinx.collections.immutable](https://github.com/Kotlin/kotlinx.collections.immutable))
to enforce a mechanism for mutability.

~~~
blauditore
Why not just Object.freeze()?

~~~
irishsultan
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.

See the example at
[https://developer.mozilla.org/en/docs/Web/JavaScript/Referen...](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)
about modifying internal.a

------
kodablah
This becomes a big problem for smart casting, e.g. if (foo.bar is Baz). If
truly immutable vals were allowed, bar could have its type assumed.

