Richard Suchenwirth 2001-12-17: Another inquiry into programming language concepts that are not (but can easily be) implemented in Tcl.
Dynamic scoping (indefinite scope and dynamic extent, as used in older LISP versions - see Tcl and LISP) means that not only local variables are visible in a command, but also those in the caller's scope, in caller's caller's scope.. right through to global scope. uplevel gives us the means to search the surrounding scopes, inside out, until we found a match, and then tie a "real" local variable to it via upvar. This nonstandard scoping has to be explicitly demanded by calling the following proc dynascope with the variable names in question:
proc dynascope args { set here [info level] foreach arg $args { for {set level 1} {$level <= $here} {incr level} { if [uplevel $level info exists $arg] { if {$level > 1} { uplevel 1 upvar [incr level -1] $arg $arg } break ;# the for loop } } } } # Now testing: set foo 1 set bar {went too far} proc a {} {set bar 2; set grill Oops..; b; puts a:bar:$bar} proc b {} {set grill 3; c; puts b:[info locals]} proc c {} { dynascope foo bar grill self nowhere set self here puts c:foo:$foo,bar:$bar,grill:$grill,self:$self puts c:nowhere:[info exists nowhere] set foo 11 set bar 22 set nowhere 33 } a
A cascade of commands is built up: a calls b, b calls c. c uses a set of dynascoped variables that we have placed on the various levels: $foo is global, $bar exists globally and in a (the two are not related), $grill both in a and in b. Dynamic scoping should stop at the nearest match, and hence "shadow" the outer variables of same name. $self is a fake dynascope var which, when not found, is created locally to c, as is $nowhere.
Disclaimer: I can think of no reasonable application for dynascope, but experimenting need not always produce useful results. At least it goes to show again that Tcl's limits are wider than my skull is...
Arjen Markus For several years I had a quotation from Francis Picabia in my room:
, then English translation being,
Experimenting with Tcl in this way is a software version of that statement.
Here is another version of variable scoping posted by kruzalex, dynascope proc leaves called variables local and setting of new values in the c scope does not change the value of the same variable in the caller's body - so it it is the same result as to use upvar 0 for every variable in c scope:
proc dynascope args { set here [info level] foreach arg $args { for {set level 1} {$level <= $here} {incr level} { if [uplevel $level info exists $arg] { if {$level > 1} { upvar $level $arg var uplevel 1 [list set $arg $var] } break ;# the for loop } } } }
Testing:
set foo 1 set bar {went too far} proc a {} { set bar 2 set grill Oops.. b puts a:bar:$bar } proc b {} { set grill 3 c puts b:grill:$grill } proc c {} { dynascope foo bar grill self nowhere set self here puts c:foo:$foo,bar:$bar,grill:$grill,self:$self puts {before changing values} puts c:foo:$foo,bar:$bar,grill:$grill set grill 4 set bar 3 set foo 2 puts {after the set of new values} puts c:foo:$foo,bar:$bar,grill:$grill } a puts $foo