Difference between upvar 0 and upvar 1 in TCL
Asked Answered
T

3

5

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.

Tame answered 12/5, 2015 at 11:39 Comment(0)
M
10

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"
Mallis answered 12/5, 2015 at 12:34 Comment(1)
Thanks alot donal i understood upvar 1 and upvar #0 very clearly and upvar 0 i understood your example, but i cant understand the real time use of upvar 0. According to my understanding it seems creating a variable name var on remember proc scope. If you make me more clear that would be fine. I am eagerly waiting for your commentsTame
D
2

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
Dynamiter answered 20/5, 2015 at 10:53 Comment(0)
A
1

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.

See http://wiki.tcl.tk/1508

Aeneas answered 12/5, 2015 at 11:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.