[Richard Suchenwirth] 2001-12-17: Another inquiry into programming language concepts that are not (but can easily be) implemented in Tcl. ** See Also ** [Namespace variables]: [Martin Lemburg]: we needed this dynascope-functionality and this functionality but across namespaces instead of scope levels. ** Description ** 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: : ''Unser Kopf ist rund, damit die Gedanken die Richtung wechseln koennen.'' , then English translation being, : ''Our heads are round, so that our thoughts can change direction.'' 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 ====== <> Concept | [Arts and crafts of Tcl-Tk programming]