Consider the following code to create linked list-like structure:
    
    
    type
      A = ref AObj
      AObj = object
        id: int
        parent: A
        child:  A
    
    proc `$`(a: A): string = $a.id
    
    
    proc takeAsVar(curr: var A, next: A) =
      if curr == nil:
        curr = next # var A is wanted here and nowhere else
      else:
        let const_curr = curr
        echo "takeAsVar: curr before: ", curr
        curr.parent.child = next # Try changing curr to const_curr for same 
result
        echo "takeAsVar: curr after:  ", curr
        # curr changes even though there is no "curr = ..." line.
    
    proc takeAsConst(curr: A, next: A) =
      if curr == nil:
        #curr = next # can't do this
        discard
      else:
        echo "takeAsConst: curr before: ", curr
        curr.parent.child = next
        echo "takeAsConst: curr after:  ", curr
    
    
    let a1 = A(id: 1, parent: nil, child: nil)
    let a2 = A(id: 2, parent: nil, child: nil)
    let a3 = A(id: 3, parent: nil, child: nil)
    
    a1.child  = a2
    a2.parent = a1
    
    takeAsVar(a1.child, a3)
    
    
    let a4 = A(id: 4, parent: nil, child: nil)
    let a5 = A(id: 5, parent: nil, child: nil)
    let a6 = A(id: 6, parent: nil, child: nil)
    
    a4.child  = a5
    a5.parent = a4
    
    takeAsConst(a4.child, a6) # Works as expected
    

which outputs
    
    
    takeAsVar: curr before: 2
    takeAsVar: curr after:  3
    takeAsConst: curr before: 5
    takeAsConst: curr after:  5
    

Notice how the value of the variable curr changes in the first proc without an 
explicit curr = ....

We have a very simple object with a parent pointer and a child pointer. My 
initial goal was to create a linked list-like structure and inserting into a 
nil list could be handled by taking the original list by var since it allows 
for curr = next. Most of the logic for non-nil list has been removed to get a 
minimum working example, but the problem is this: When I want to change the 
child field of the parent of curr, then the variable curr itself is changed 
when taken by var.

In my mind taking a parameter by var would only change whether you can write 
curr = ... and change the original or not. Here it seems that it somehow infers 
that curr.parent.child is the same as curr and changes curr as well.

Have I misunderstood how var parameters work? Is this desired behaviour?

Using version 0.16.1 (git hash: 137b5f43022c3c5e22a7f28c8012f1d0ea6007c6)

Reply via email to