Richard Suchenwirth 2006-06-05 - "Environment" is understood here as a set of variables and their values, like many operating systems make available to processes (in Tcl, the
env variable mirrors that).
There may be situations when you want to provide a local environment from one
proc A to another, B, without having to build a long argument list, nor having to use
global variables. Other languages with lexical scoping, like
Lisp, have that as built-in feature, but here's a simple way how to do that in Tcl: a {name value name value...} list is wrapped, passed to the called function, which in turn unwraps it. You have to specify which variables shall go in, that's why I call it "controlled environment" :^)
Usage ("name" being a freely choosable variable name):
env name add var... ;# in the caller, who calls the callee with $name
env name get ;# in the callee
Only scalar variables can be wrapped. The callee gets copies of the variables which he can change at will, without influencing the "originals" in the caller. Both features mirror those of OS environment variables.
proc env {_name mode args} {
upvar 1 $_name var
switch -- $mode {
add {foreach n $args {lappend var $n [uplevel 1 set $n]}}
get {foreach {n val} $var {uplevel 1 [list set $n $val]}}
default {error "bad mode $mode, use add or get"}
}
}
#-- Testing (the example should leave no question open):
proc caller arg {
set foo 42
set bar grill
env e add arg foo bar
callee 123 $e
}
proc callee {x e} {
env e get
foreach name [info vars] {
lappend res $name=[set $name]
}
set res
}
puts [caller hello!]
which returns:
x=123 {e=arg hello! foo 42 bar grill} foo=42 bar=grill arg=hello!
See also
closures.
NEM: In particular, see
Simple Closures and Objects, which does a similar thing, but using
dict with to restore the environment in the new scope.