Can anyone let me know the difference between upvar 0
and upvar 1
in TCL, how we can use in real time. Kindly, if someone explain with example, it makes me more clear.
When you are calling a bunch of procedures, you get a stack of stack frames. It's in the name. We might visualise this like so:
abc 123 456 bcd 321 456 cde 654 321
OK, so we've got abc
calling bcd
calling cde
. Simple.
The 0
and 1
in upvar
say how many levels to go up the stack when looking up the variable to link to. 1
means go up one level (i.e., to the caller of the current frame), say from cde
to bcd
in our example, 2
would go from cde
up to abc
and 3
all the way up to the global evaluation level where overall scripts and callbacks run. 0
is a special case of this; it means do the lookup in the current stack frame. There's also the ability to use indexing from the base of the stack by putting #
in front of the name, so #0
indicates the global frame, #1
the first thing it calls.
The most common use of upvar
is upvar 1
(and if you leave the level out, that's what it does). upvar 0
is only really used when you want to get a different (usually easier to work with) name for a variable. The next most common one is upvar #0
, though global
is a much more common shorthand there (which matches the unqualified parts of the name for your convenience). Other forms are rare; for example, upvar 2
is usually an indication of really confusing and tangled code, and hardly anyone ever used upvar #1
before Tcl 8.6's coroutines. I've never seen upvar 3
or upvar #2
in the wild (though computed level indicators are present in some object systems for Tcl).
Example of upvar 1
— pass variable by name:
proc mult-by {varName multiplier} {
upvar 1 $varName var
set var [expr {$var * $multiplier}]
}
set x 2
mult-by x 13
puts "x is now $x"
# x is now 26
Example of upvar 0
— simplify variable name:
proc remember {name contents} {
global my_memory_array
upvar 0 my_memory_array($name) var
if {[info exist var]} {
set var "\"$var $contents\""
} else {
set var "\"$name $contents\""
}
}
remember x 123
remember y 234
remember x 345
remember y 456
parray my_memory_array
# my_memory_array(x) = ""x 123" 345"
# my_memory_array(y) = ""y 234" 456"
unlike upvar 1 , upvar 0 creates alias for the variable. for ex:
set a 4
proc upvar1 {a} {
upvar 1 a b
incr a 4
incr b 3
puts "output is $a $b"
}
proc upvar0 {a} {
upvar 0 a b
incr a 4
incr b 3
puts "output is $a $b"
}
upvar1 $a
puts "in global frame value of a is $a"
set a 4
upvar0 $a
puts "in global frame value of a is $a"
Output:
output is 8 7
in global frame value of a is 7
output is 11 11
in global frame value of a is 4
Ok I think an example will make the difference quite clear:
Lets say we have a function test_upvar1:
proc test_upvar1 {} {
upvar 1 a b
incr b
}
And a function test_upvar0:
proc test_upvar0 {} {
upvar 0 a b
incr b
}
Now we set variable a and call both function to see what happens:
set a 5
test_upvar1
This will return 6
set a 5
test_upvar0
Will return 1
This happens because we select with zero and one our execution frame 0 links in the same execution frame 1 a frame higher.
© 2022 - 2024 — McMap. All rights reserved.