So ... since this idea is not yet RFC-ready, let me post my recent musings
here: Immutability in Nim is not attached to a type, but to a "symbol kind",
`let` variables are immutable, `var` variables are mutable, parameters are
immutable unless `var` and the world is nice and clean and this system works
exceptionally well.
However, there is one problem: `ref`. Nim's immutability is deep until the
first `ref` comes into play. This is a loophole in Nim that we could fix. We
have known an algorithm for computing "deep immutabilty" (so called "write
tracking") for quite some time now, but it never was obvious about how to add
it _syntactically_ to Nim nor what the default should be.
So here is my idea: Extend the immutability to `ref` in parameters and
introduce a single symbol called `mut` to make them mutable. `mut` would be a
parameter passing mode, it's not a general type constructor, so the following
will **not** compile:
type
Node = ref object
le, ri: mut Node
Run
Some examples that **would compile** :
type
Node = ref object
data: string
le, ri: Node
proc m(n: mut Node) =
n.data = "xyz"
proc depth(n: Node): int =
(if n == nil: 0 else: max(depth(n.le), depth(n.ri) + 1)
Run
Some examples that would not compile:
proc depth(n: Node): int =
m(n) # error: cannot pass 'n' to a 'mut Node'
result = (if n == nil: 0 else: max(depth(n.le), depth(n.ri) + 1)
proc main =
let n = Node(data: "abc", le: nil, ri: nil)
n.data = "xyz" # error: cannot mutate via a ``let`` binding.
Run
As you can see, the concept naturally extends to `let` variables, these can
become deeply immutable too.
# Q&A
1\. Why not simply use `var T` instead of `mut T`?
> `var T` is a hidden pointer and so `var ref T` creates a pointer to a
> pointer. This has negative effects on the subtype relation, you cannot pass a
> subtype of `ref T` to a `var ref T`.
2\. Why not simply change what `func` means?
> Orthogonality, `func` is a shortcut for `.noSideEffect` and Nim also has
> iterators, methods, converters, that would also benefit from deep immutabilty.
3\. Why not make it a `writes` effect instead? Let the compiler infer it.
> The effect system doesn't work too well with generics and produces harder to
> understand error messages for newcomers, I don't want to extend it even
> further. Furthermore the computed effects currently do not cover parameter
> passing semantics, parameter passing semantics are too important IMO, they
> are better spelt out explicitly.