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.

Reply via email to