RHS 12August2004
A package for treating parts of one variable as a whole other variable. More description to come later, but the basic idea (via some of the tests) is:
test list.stackLevels-1.1 { Passing the name of a child into a proc to be upvar'd\ will still modify the parent } -setup { reset main child } -body { proc modify {&var} { upvar 1 ${&var} var set var [string toupper $var] } set main {a b {c d} e} shadow child main 2 modify child set main } -result {a b {C D} e} test array.stackLevels-1.1 { Pass the child into a proc, and change it via upvar } -setup { reset main child } -body { proc modify {&var} { upvar 1 ${&var} var foreach {key value} [array get var] { set var($key) [expr {$value * 20}] } } array set main {a 1 b 2 c 3} shadow child main modify child getArraySorted main } -result {a 20 b 40 c 60} test array.element-1.1 { Shadow an array element, parent follows the 'array get'\ value of the child } -setup { reset main child } -body { array set main {a {A 1} b {B 2}} shadow child main b set child(B) [expr {$child(B) * 2}] getArraySorted main } -result {a {A 1} b {B 4}}
Feel free to take a look at the code for it at http://robert.rkseeger.net/tcl/shadow/shadow.tar.gz for now. I'll write up more information on what I was trying to do, and the limits of that approach, some other time.
RS 2004-08-17: Here's a very simple version that works only on lists, by linking a scalar variable to an element of the given list, and updating the list when the variable is changed (or re-reading the element from the list when the variable is read):
proc llink {listVar index linkVar} { upvar 1 $listVar list $linkVar link set link [lindex $list $index] trace add variable link {read write} [list llink'rw $listVar $index] } proc llink'rw {listVar index name el op} { upvar 1 $listVar list $name link switch -- $op { read {set link [lindex $list $index]} write {set list [lreplace $list $index $index $link]} } }
# Testing:
% set list {a b c} a b c % llink list 2 link % set link hello hello % set list a b hello % llink list 1 link2 % set link2 world world % set list a world hello % set list {d e f} ;# testing the other direction too d e f % set link2 e % set link f
RHS Indeed, thats pretty much what the code I wrote does, but it handles fringe conditions a little better. For example:
% set list {a b c} a b c % llink list 2 link % proc bob {var} { upvar $var myvar ; set myvar uhoh } % bob link can't set "myvar": can't read "list": no such variable
And
% set list {a b c} a b c % llink list 2 link % unset list % set link goodbye can't set "link": can't read "list": no such variable
I wanted to make sure my code would work in those situations, as well as be able to link variables to array elements.