I try use the `var` `let` and `mut` to test some scenario. First, we define the 
meaning of these terms(all for ref T type).
    1\. `let` means fixed readonly variable binding, parameter without `var` 
means `let` binding
    
    
    proc p1() =
       let x = Node()
       x.left = nil      # invalid   change value
       x = Node()        # invalid   change variable binding
    
    proc p2(x: Node) =
       x.left = nil      # invalid   change value
       x = Node()        # invalid   change variable binding
    
    
    Run

> 2\. `var` means mutable variable binding, we can change the value, and we can 
> change the variable binding if it is local variable; we cannot change the 
> variable binding if it is parameter, so the compiler needn't pass pointer of 
> pointer to caller.
    
    
    proc p1() =
       var x = Node()
       x.left = nil      # valid
       x = Node()        # valid
    
    proc p2(x: var Node) =
       x.left = nil      # valid
       x = Node()        # invalid   change variable binding
    
    
    Run

> 3\. `mut` means the variable binding can be changed only, it can be used with 
> `let` and `var` in parameter.
    
    
    proc p1() =
       let mut x = Node()
       x.left = nil      # invalid   change value
       x = Node()        # valid
    
    # it can be used to traverse the graph or list
    proc traverse(n: Node) =
       let mut x = n     # valid
       while not x.isNil:
          x = x.right    # valid
    
    proc p2(x: mut Node) =
       x.left = nil      # invalid
       x = Node()        # valid
    
    proc p3(x: var mut Node) =
       x.left = nil      # valid
       x = Node()        # valid
    
    
    Run

To make rule simple and clear, readonly variable cannot be assigned to any 
`var` variable or field. 
    
    
    proc p1(v1: Node) =
       let v2 = Node()
       var x = Node()
       x = v1            # invalid
       x.left = v2       # invalid
    
    
    Run

Sometime we need assign a readonly variable to `var` variable, we introduce 
`{.mut.}` pragma, suppose the programmer know what he is doing(With ptr he can 
do anything). 
    
    
    proc p1(v1: Node) =
       var cache {.mut.} : seq[Node] = @[]
       cache.add v1      # valid, with {.mut.}, it can hold readonly variable
       
       var x {.mut.} = v1   # valid
    
    
    Run

Sometime we need to build immutable object with constructor or builder, we can 
introduce `{.cons.}` pragma, which means the proc `result` value can hold 
readonly object. 
    
    
    proc createNode(ll, rr: Node): Node {.cons.} =
       result = Node()
       result.left = ll     # valid
       result.right = rr    # valid
    
    
    Run

Reply via email to