[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 to a proc, 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 procs 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 will not be found, so 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. (For those not literate in German: Our heads are round, so that our thoughts can change direction) Experimenting with Tcl in this way is a software version of that statement. ---- [Martin Lemburg]: we needed this dynascope-functionality and this functionality but across namespaces instead of scope levels ... see [Namespace variables] ---- Here is another version of variable scoping posted by kruzalex, dynascope proc leaves called variables local and seting of new values in the c scope does not change the value of the same variable in the callers body - so it it is the same result as to use uplevel 0 for every variabla in c scope proc dynascope args { global first set first 0 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 } } } } # 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: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 ---- [Category Concept] | [Arts and crafts of Tcl-Tk programming]