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)
I must have been tired when I wrote this code. I am pretty certain that I understand how the indirection works now. I just remember thinking that it was super weird that I could change something and then another variable suddenly changed its contents. But of course they pointed to the same thing behind the scenes.
Sorry for the inconvenience and thank you for the reply!