|
|
 |
 |
 |
 |
TCL(Tool Command Language) Scripting
|
 |
 |
 |
 |
 |
 |
 |
 |
Upvar confusion
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
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.
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
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
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 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
In article <1179762854.244031.238@z24g2000prd.googlegroups.com>, Alexandre Ferrieux <alexandre.ferri@gmail.com> wrote:
>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 ?
. . . 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".
Neil Madden wrote: > 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
but using it with 2 or 3 is so much fun! Bruce
Bruce Hartweg schrieb: > Neil Madden wrote: >> 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 > but using it with 2 or 3 is so much fun! > Bruce
Combine with [return -level] with level 2 or 3 for even more fun! Michael
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
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
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.
At 21 May 2007 14:09:26 -0700 Alexandre Ferrieux <alexandre.ferri@gmail.com> wrote:
> 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++
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
In article <1179781766.794252.288@a26g2000pre.googlegroups.com>, Alexandre Ferrieux <alexandre.ferri@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.
In article <1179781766.794252.288@a26g2000pre.googlegroups.com>, Alexandre Ferrieux <alexandre.ferri@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. . . .
Michael Schlenker <schl @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 a@triumf.ca
|
 |
 |
 |
 |
|