Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Unable to understand "uplevel" and "upvar" in TCL

3,739 views
Skip to first unread message

Ahmed Omara

unread,
Dec 20, 2010, 7:17:08 PM12/20/10
to
Hi,

I have never been able to understand "uplevel" and "upvar" in TCL and
when to use them?

Can anyone explain this to me in a way that I can understand, with
examples please?

Thanks,
Ahmed

Googie

unread,
Dec 21, 2010, 2:45:09 AM12/21/10
to
Ahmed Omara wrote:

They are highly useful when implementing your own control structures, but
it's not limited to. They make many tricky hacks possible.

Example for "uplevel" usage:

Let's say you want to implement procedure "fec" which means "for every
character", which syntax is:

fec varName string code

Then you define:

###########################
proc fec {varName string code} {
uplevel [list \
foreach $varName \[split $string {}] {
eval $code
}
]
}
###########################

I don't know if this code works - I just wrote it here to present usage of
"uplevel".
The whole "foreach" loop will be executed on upper level of stack, so if you
execute:

set var1 "x"
fec v "abc" {puts "$var1, $v"}

then the code of "fec"'s body will resolve $var1 as it should, because that
whole body code is executed at the same stack level as: set var1 "x"


Now example for "upvar" usage:

The "upvar" is somehow similar to "passing value by reference" in C++.
Commands like "lappend" would use it if they were not implemented in C (in
Tcl core). Here's a pseudo-code for "lappend" implemented in Tcl:

proc lappend {varName args} {
upvar $varName var

if {![info exists var]} {
set var [list]
}

foreach arg $args {
if {[llength $var] == 0} {
set var [list $arg]
} else {
set var [concat $var [list $arg]]
}
}
}

See? We make a "link" with upper variable named as passed in $varName to
local variable named "var", so we can use "var" variable locally as usual
and then any changes made to "var" are also made to variable named as value
of $varName on upper level of execution stack:

--
Pozdrawiam! (Regards!)
Googie

Donal K. Fellows

unread,
Dec 21, 2010, 3:17:27 AM12/21/10
to
On Dec 21, 7:45 am, Googie <n...@spam.0rg> wrote:
> I don't know if this code works - I just wrote it here to present usage of
> "uplevel".

Try this version which does work:

proc fec {varName string body} {
uplevel 1 [list foreach [list $varName] [split $string {}] $body]
}

I prefer a longer example of [uplevel] (and [upvar] too):

proc foreachline {varName fileName body} {
upvar 1 $varName line
set f [open $fileName]
while {[gets $f line] >= 0} {
uplevel 1 $body
}
close $f
}

That makes it easy to process lines from a file, one at a time. It
even supports the control constructs [break] and [continue]; Tcl
really is that easy. Example of usage:

# Simple (incomplete) INI parser
foreachline l foo.ini {
# Comment
if {[string match ";*" $l]} {
continue
}
# Section
if {[regexp {^\[(.*)\]$} $l -> topic]} {
set section $topic
}
# Property
if {[regexp {^(\w+)=(.*)} $l -> name value]} {
dict set properties($section) $name $value
}
}

> The "upvar" is somehow similar to "passing value by reference" in C++.

Here's how to do the [global] command in pure Tcl:

proc global args {
foreach var $args {
uplevel 1 [list upvar #0 $var $var]
}
}

The other thing to note about [upvar] is that it creates very
efficient connections between local variables and the other variables.
(So too does [global] and [variable].)

Donal.

Neil

unread,
Dec 21, 2010, 11:51:22 AM12/21/10
to
> Can anyone explain this to me in a way that I can understand, with
> examples please?

Doing so for sure requires understanding what you understand...

Do you understand 'scope', and if so, what languages are you familiar
with it in? (and if not, what languages are you familiar with?)

jemptymethod

unread,
Dec 21, 2010, 8:47:12 PM12/21/10
to

I am going to quote liberally from "Tcl and the Tk Toolkit, 2nd ed.",
pg. 149, as to upvar:

"The upvar command provides a general mechanism for accessing
variables outside the context of a procedure....If 'a' is an array,
you cannot pass it to a procedure ... because there is no value for an
array as a whole; there are values only for the individual elements.
Instead you can pass the name of the array to the procedure ... and
use the upvar command to access the array's elements from the
procedure."

"Here is a simple example...."

proc printArray {name} {
upvar $name a
foreach el [lsort [array names a]] {
puts "$el = $a($el)"
}
}

set info(age) 37
set info(position) "Vice President"

printArray info

output:
"age = 37"
"position = Vice President"


Hope this helps

vinodk...@gmail.com

unread,
Feb 21, 2018, 2:57:20 AM2/21/18
to
Upvar is like call by reference.see my below example for upvar


%
% proc hi {varname} {
upvar $varname ok
set ok 1
}
%
% set yes 2
2
% hi yes
1
% puts $yes
1

Mike Griffiths

unread,
Feb 21, 2018, 5:41:45 AM2/21/18
to
You'd need to use [upvar] to code your own version of something like [incr], which takes a variable name as an argument, and changes the value of the variable in the calling scope. To give a similar example...

proc double {_varname} {
upvar 1 $_varname var;
set var [expr {$var * 2}]
}

% set x 5
5
% double x
10
% double x
20

The first arg to upvar is the number of levels of scope to go up (1 means 'where the current proc was called from', and is probably the most common, alongside #0, which is 'global scope').
The next arg is the variable in that scope we want to affect, in this case, 'x' (which is passed in to the proc as $_varname).
The final arg is the name of the local variable to use to refer to the var we're affecting, in this case, 'var'.
So now, whenever we get (or set) the value of the local variable $var, we're actually getting/setting the value of the variable $x in the calling scope.

Rich

unread,
Feb 21, 2018, 6:47:39 AM2/21/18
to
vinodk...@gmail.com wrote:
> On Tuesday, 21 December 2010 05:47:08 UTC+5:30, k3wb wrote:
>> Hi,
>>
>> I have never been able to understand "uplevel" and "upvar" in TCL and
>> when to use them?
>>
>> Can anyone explain this to me in a way that I can understand, with
>> examples please?
>>
>> Thanks,
>> Ahmed
>
> Upvar is like call by reference.see my below example for upvar

You *do* realize that you just replied to a posting that is almost
eight years old, don't you?

Mike Griffiths

unread,
Feb 21, 2018, 4:08:03 PM2/21/18
to
*laughs* I did not when I put my two cents in. Well spotted. ;)

Ricardo kozmate.net

unread,
Feb 21, 2018, 5:51:39 PM2/21/18
to
Em 21/02/18 10:41, Mike Griffiths escreveu:
> proc double {_varname} {
> upvar 1 $_varname var;
> set var [expr {$var * 2}]
> }
Since we're picking up a 8 y.o. issue, let's try to make some use of it :-)


I understand the concept - at least enough for basic usage as in the
example. What surprises me a little is the need to use different
variable names, i.e., couldn't we have (also?) something as:

proc double {var} {
upvar 1 var
set var [expr {$var * 2}]
}


or "upvar 1 $var" or whatever, while keeping the name.

Why not?


--
{ricardo from kozmate.net}

Ratnendra Pandey

unread,
Nov 22, 2020, 7:47:34 PM11/22/20
to
The topic was originally created 10 years ago. But, I learned from it today, almost 10 years later. Thanks to all who answered this question.
0 new messages