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

Upvar confusion

14 views
Skip to first unread message

Kevin Walzer

unread,
May 21, 2007, 11:15:39 AM5/21/07
to
I'm having a bit of trouble getting my head around upvar. I understand
it is a powerful mechanism, and used a great deal in Tcl, but I've also
looked at ESR's caution that upvar is "rather dangerous if not used with
great caution."

When using variables in a Tcl package that defines its own namespace, I
have found it helpful to use this structure:

variable foo

proc myProc {bar} {
set foo $bar
}

This allows me to keep a clean separation between global namespace
variables and variables that are local in scope.

If I'm reading the upvar man page correctly, I could do this:

variable foo

proc myProc {bar} {
upvar $bar foo
}


My question is, what is the advantage of doing it this way?

--
Kevin Walzer
Code by Kevin
http://www.codebykevin.com

mark anthony

unread,
May 21, 2007, 11:48:20 AM5/21/07
to
On May 21, 5:15 pm, Kevin Walzer <k...@codebykevin.com> wrote:

namespace eval variable {


variable foo
proc myProc {bar} {

variable foo
set foo $bar
}
}
namespace eval upvar {


variable foo
proc myProc {bar} {
upvar $bar foo
}
}

if you call

variable::myProc "lorem ipsum dolar"

you set variable::foo to "lorem ipsum dolar"

while if you call upvar::myProc "lorem ipsum dolar"
you will gain access to the variable "lorem ipsum dolar"
from the callers scope (not the namespace)

e.g.

proc some { } {
set string ""
upvar::myProc string
}

so now foo inside myProc is nothing
other then the variable string from
inside some.

so these two procs do something completely different

cheers,
mark.

Alexandre Ferrieux

unread,
May 21, 2007, 11:54:14 AM5/21/07
to
On May 21, 5:15 pm, Kevin Walzer <k...@codebykevin.com> wrote:
> I'm having a bit of trouble getting my head around upvar. I understand
> it is a powerful mechanism, and used a great deal in Tcl, but I've also
> looked at ESR's caution that upvar is "rather dangerous if not used with
> great caution."

I don't know whom you're abbreviating as ESR, but I find it very
strange to call anything "dangerous" when it has no side effects
outside the memory of the current process. The adjective is better
suited to things like "rm /sbin/init"...

The construct [upvar a b] creates a "tunnel" from the current scope,
where the entry of the tunnel looks like a local named "b", to the (if
any) variable "a" in the parent scope. I say "if any", because [info
exists b] is consistent with the existence of "a", as are the "no such
variable" raised if you try to access "b" when "a" doesn't exist.

Notice that the local name "b" must be available (i.e not used by a
variable), otherwise [upvar] raises 'variable "b" already exists'.

> proc myProc {bar} {
> set foo $bar
>

> proc myProc {bar} {
> upvar $bar foo

If you follow the definition, the latter creates a local 'foo'
tunneling to whatever is named $bar upwards. Notice this doesn't
"collide" with the namespace-global foo, since we are in the local
scope.

I fail to see what you're driving at though; do you realize that the
two code snippets above do things completely different ?

-Alex

Bryan Oakley

unread,
May 21, 2007, 12:50:06 PM5/21/07
to
Kevin Walzer wrote:
> I'm having a bit of trouble getting my head around upvar. I understand
> it is a powerful mechanism, and used a great deal in Tcl, but I've also
> looked at ESR's caution that upvar is "rather dangerous if not used with
> great caution."

Maybe the best way to think about upvar is to answer the question "how
would I write a command like 'set' in pure tcl?"

upvar is specifically for that type of problem. It's for when you want
to pass in the name of a variable and be able to directly modify that
variable.

It's definitely one of the commands that I personally almost never, ever
use. But the few times I use it, it's not just the right tool for the
job, it's the only tool.

--
Bryan Oakley
http://www.tclscripting.com

Neil Madden

unread,
May 21, 2007, 12:41:12 PM5/21/07
to
Kevin Walzer wrote:
> I'm having a bit of trouble getting my head around upvar. I understand
> it is a powerful mechanism, and used a great deal in Tcl, but I've also
> looked at ESR's caution that upvar is "rather dangerous if not used with
> great caution."

I don't think Eric Raymond has used Tcl for a very long time, so I'd
take his advice with a healthy pinch of salt. Upvar and uplevel are
somewhat advanced tools, but "dangerous" is an overstatement.

> When using variables in a Tcl package that defines its own namespace, I
> have found it helpful to use this structure:
>
> variable foo
>
> proc myProc {bar} {
> set foo $bar
> }
>
> This allows me to keep a clean separation between global namespace
> variables and variables that are local in scope.
>
> If I'm reading the upvar man page correctly, I could do this:
>
> variable foo
>
> proc myProc {bar} {
> upvar $bar foo
> }

No, that probably won't do what you expect. [upvar] creates a link
between a variable in the calling scope and a local variable so that
changes to one are reflected in the other. Therefore you should only use
upvar if this is what you want to happen (i.e., you want to change the
value of a variable in the caller's scope). If you just want to pass in
the value of a variable then avoid upvar and do things like you normally do:

variable foo
proc myproc bar {


variable foo
set foo $bar
}

myproc $someValue

which can be shortened to just:

proc myproc bar {
variable foo $bar
}

To illustrate what upvar does, consider this replacement for [incr]:

proc myIncr {varName {amount 1}} {
upvar 1 $varName var
set var [expr {$var + $amount}]
}
set foo 12
myIncr foo ;# note: no $, just like incr
puts $foo ;# prints 13

Both upvar and uplevel can be used to create some very elegant
interfaces, but they can also decrease readability of the
implementation, so should be used sparingly. Also, you should always
specify the "level" argument and that argument should only ever be given
a value of "1" or "#0". If you think you need any other value then your
proc should itself take a level argument (and incr it). See
http://wiki.tcl.tk/18024 for an example of this.

-- Neil

Neil Madden

unread,
May 21, 2007, 12:57:10 PM5/21/07
to
Neil Madden wrote:
...

> Also, you should always
> specify the "level" argument and that argument should only ever be given
> a value of "1" or "#0".

Or "0", before someone corrects me...

-- Neil

Cameron Laird

unread,
May 21, 2007, 1:43:04 PM5/21/07
to
In article <1179762854.2...@z24g2000prd.googlegroups.com>,
.
.
.
Alexandre handles the main content without my help. I'll
address a few tangential factual matters.

"ESR" is Eric Raymond; he comes up (this morning, at least)
as Google's first hit for "esr" (even before "erythrocyte
sedimentation rate"!). Alexandre, he's a ... celebrity of
the open-source world. The remark about upvar (and uplevel
as well) appears in, for example, <URL:
http://www.faqs.org/docs/artu/ch14s04.html >, which is about
as close to primary as anything published--Eric had been
saying this for some time in person.

And he's not alone. I have fairly reliable memories of Mark,
Jeff, Clif, maybe Donal, ... and I also linking "danger" and
"upvar" at various times. I'll try to make it less strange
to you: the good uses for upvar all involve side effects--and
side effects, like gotos and double dereferencing and
threading and several other items, are intrinsically
problematic. *You* correctly understand upvar: it expresses
a specific and well-controlled side effect. It's no more
dangerous than a hatchet, which is simply made to do a
demanding task.

As the same time, we don't put hatchets in the hands of
infants, not without training. I suspect the real danger of
upvar is that we haven't yet figured out how to teach or
document it efffectively; too many newcomers (and not-so-new-
comers) to Tcl end up hurting themselves with upvar. You
don't, Alexandre, but of course you have a more mathematical
understanding of Tcl in general.

I'm not sure what to say to help Kevin. I'm inclined to
advice that is terse: "don't use upvar unless you know you
must".

Bruce Hartweg

unread,
May 21, 2007, 3:20:07 PM5/21/07
to

but using it with 2 or 3 is so much fun!

Bruce

Michael Schlenker

unread,
May 21, 2007, 4:42:49 PM5/21/07
to
Bruce Hartweg schrieb:

Combine with [return -level] with level 2 or 3 for even more fun!

Michael

Alexandre Ferrieux

unread,
May 21, 2007, 5:09:26 PM5/21/07
to
On May 21, 7:43 pm, cla...@lairds.us (Cameron Laird) wrote:
>
> "ESR" is Eric Raymond; he comes up (this morning, at least)
> as Google's first hit for "esr" (even before "erythrocyte
> sedimentation rate"!). Alexandre, he's a ... celebrity of
> the open-source world. The remark about upvar (and uplevel
> as well) appears in, for example, <URL:http://www.faqs.org/docs/artu/ch14s04.html>, which is about
> as close to primary as anything published--Eric had been
> saying this for some time in person.

Thanks for the clarification. Of course I know about Eric Raymond,
however I had never associated him with Tcl more than on a general
level (never seen him here for example). Now to think he could express
strong feelings about [upvar]...

Looking at the URL you provide, it looks like his contact with Tcl is
a bit superficial ("...the rules for when things need to be quoted or
braced are a bit tricky..."). And singling out [upvar] in a language
overview like this one, is a very strange choice; especially so when
you consider the role of [upvar] (and [uplevel]) as a key enabler of
first-class control structures...

> [...] I suspect the real danger of


> upvar is that we haven't yet figured out how to teach or
> document it efffectively; too many newcomers (and not-so-new-
> comers) to Tcl end up hurting themselves with upvar.

Possibly so. However, a 2nd-day C++ trainee learns about var-by-
reference in prototypes.
By analogy I tend to believe a 2nd-day Tcler could learn by heart an
idiom like

proc foo {x y vz vt} {
upvar $vz z
upvar $vt t
...
}

and master the full generality (with levels 0,1, and #0) much later.
I'm not that keen on reference args in C++ by the way (nor on C++
itself...), but in Tcl there is a noticeable gap in "stylistic
efficiency" when you're allowed to [upvar]. Alternatives are globals
(yuck!) and endless (de/)serialization like in

foreach {z t} [foo $x $y] break

or even, with an array:

array set bar [foo $x $y]

> I'm not sure what to say to help Kevin. I'm inclined to
> advice that is terse: "don't use upvar unless you know you
> must".

Agreed -- if you allow a bit of generalization again :-)

foreach gotcha {threads embedding comm eof upvar} {
puts "don't use $gotcah unless you know you must"
}

(sorry -- just couldn't resist)

-Alex

Uwe Klein

unread,
May 21, 2007, 5:30:57 PM5/21/07
to
Alexandre Ferrieux wrote:
> On May 21, 7:43 pm, cla...@lairds.us (Cameron Laird) wrote:
>
>>"ESR" is Eric Raymond; he comes up (this morning, at least)

Mr Raymond is a Pythonista and a politico at heart.

in that position you have to be noticable and precise
in your verdict.

You need not necessarily be correct.

uwe

Donal K. Fellows

unread,
May 21, 2007, 5:48:49 PM5/21/07
to
Neil Madden wrote:
> Also, you should always
> specify the "level" argument and that argument should only ever be given
> a value of "1" or "#0". If you think you need any other value then your
> proc should itself take a level argument (and incr it).

I've actually used '2' as a hard-coded level in production code (it
was a custom OO system, where the level in between was the object
context manager procedure). It was so complex that I recoded the guts
of what I was doing in C instead though, and that made everything much
more conventional. This was back in Tcl 7.5 though, with no
namespaces. Life is much easier these days!

Donal.

Robert Heller

unread,
May 21, 2007, 7:26:55 PM5/21/07
to

Then you'd probably hate FORTRAN:

Clasic FORTRAN error (can you spot it?):

Program NotOne
implicit none a-z
integer A
A = 1
Call Incr(1)
A = A + 1
print 100,A
100 Format(' A = ',I4)
end
Subroutine Incr(X)
implicit none a-z
integer X
X = X + 1
Return
end

Hint: FORTRAN *always* passes by reference.

> itself...), but in Tcl there is a noticeable gap in "stylistic
> efficiency" when you're allowed to [upvar]. Alternatives are globals
> (yuck!) and endless (de/)serialization like in
>
> foreach {z t} [foo $x $y] break
>
> or even, with an array:
>
> array set bar [foo $x $y]
>
> > I'm not sure what to say to help Kevin. I'm inclined to
> > advice that is terse: "don't use upvar unless you know you
> > must".
>
> Agreed -- if you allow a bit of generalization again :-)
>
> foreach gotcha {threads embedding comm eof upvar} {
> puts "don't use $gotcah unless you know you must"
> }
>
> (sorry -- just couldn't resist)
>
> -Alex
>
>

--
Robert Heller -- 978-544-6933
Deepwoods Software -- Linux Installation and Administration
http://www.deepsoft.com/ -- Web Hosting, with CGI and Database
hel...@deepsoft.com -- Contract Programming: C/C++, Tcl/Tk

Cameron Laird

unread,
May 21, 2007, 7:09:09 PM5/21/07
to
In article <1179781766.7...@a26g2000pre.googlegroups.com>,
Alexandre Ferrieux <alexandre...@gmail.com> wrote:
.
.

.
>Looking at the URL you provide, it looks like his contact with Tcl is
>a bit superficial ("...the rules for when things need to be quoted or
>braced are a bit tricky..."). And singling out [upvar] in a language
>overview like this one, is a very strange choice; especially so when
>you consider the role of [upvar] (and [uplevel]) as a key enabler of
>first-class control structures...
.
.
.
I have a strong prejudice that anyone who characterizes
Tcl as "tricky" in its quoting ("grouping", as Gerald,
Bryan, and others rightly prefer) understands the
language only superficially. Eric's far from the only
one to write this; I regard him as no counter-example to
my rule.

Cameron Laird

unread,
May 21, 2007, 7:13:56 PM5/21/07
to
In article <1179781766.7...@a26g2000pre.googlegroups.com>,
Alexandre Ferrieux <alexandre...@gmail.com> wrote:
.
.

.
>Possibly so. However, a 2nd-day C++ trainee learns about var-by-
>reference in prototypes.
>By analogy I tend to believe a 2nd-day Tcler could learn by heart an
>idiom like
>
> proc foo {x y vz vt} {
> upvar $vz z
> upvar $vt t
> ...
> }
>
>and master the full generality (with levels 0,1, and #0) much later.
>I'm not that keen on reference args in C++ by the way (nor on C++
>itself...), but in Tcl there is a noticeable gap in "stylistic
>efficiency" when you're allowed to [upvar]. Alternatives are globals
>(yuck!) and endless (de/)serialization like in
>
> foreach {z t} [foo $x $y] break
>
>or even, with an array:
>
> array set bar [foo $x $y]
Quite so! Moreover, we've both rather slid by the case of
arrays, and how some of what we're not saying won't need to
be said with general availability of dictionaries.

Hmmm; maybe Richard's wikibook deserves a chapter on the wise
use of upvar and other hazards (see below).
.
.


.
>Agreed -- if you allow a bit of generalization again :-)
>
> foreach gotcha {threads embedding comm eof upvar} {
> puts "don't use $gotcah unless you know you must"
> }
>
>(sorry -- just couldn't resist)

I do not merely allow it; it tickles me.
.
.
.

Donald Arseneau

unread,
May 21, 2007, 8:55:03 PM5/21/07
to
Michael Schlenker <sch...@uni-oldenburg.de> writes:

> Combine with [return -level] with level 2 or 3 for even more fun!

Even with old versions of Tcl, there is
return -code return
which seems a reasonable context to use
upvar 2

I have used the return, but I don't think I've ever used the
upvar 2.

--
Donald Arseneau as...@triumf.ca

0 new messages