I have the following procedures setup to mimick constants. All works
ok when I define my constants, including arrays. However, when arrays
are made with this setup, the command:
array names <array_name>
returns an empty string. Can anyone explain why? Especially, since
if I define constant values with this as arrays, they seem to function
correctly as arrays.
Here's the code:
namespace eval traps {
proc _constant_trap { val name1 name2 ops } {
# read up on the trace protocol for the arguments above
upvar $name1 var
if { $name2 == "" } {
# we're not looking at an array here
set var $val
} else {
set var($name2) $val
}
}
}
proc ::define { varName { value 1 } } {
uplevel [list trace add variable $varName "read write" \
[list ::traps::_constant_trap $value]]
}
So, in my scripts I do something like:
define ::ary(elem1) "something"
define ::ary(elem2) "something else"
Then when I do things like this:
puts $ary(elem1)
proc test { } {
global ary
puts $ary(elem1)
puts $ary(elem2)
}
Everything works as one would expect it to work. However, as noted
before, the command "array names ary" returns an empty string. Why is
this?
Andy
A little experimentation has revealed to me that with how I have
things setup in my callback, etc., these variables aren't actually
created until they are accessed for the first time.
Ok, so that's the problem. Can anyone offer a decent solution to this
problem while still preserving the "constant" value of these
variables? One of the things I'm thinking now is to set the variable
in the procedure define before registering the callback. This would
seem to make the most sense, or since the call back will make it
happen too, I could simply access the variable in the define procedure
before exiting the define proc. Any suggestions that are more elegant
than these?
Andy
I've written some time ago a package named const to const'ify scalar
variables and arrays, perhabs this source could help you.
The source is not too big, but I won't post it here. Instead of
posting it I created a wiki page for it:
But ... to and about your source ...
1. why do you trace read events?
2. array's can contain an element with the an empty string as name,
so ...
% set array() 1
1
... is possible! So your procedure "_constant_trap" would fail!
It would be better to detect the type of the "data holder" (array or
scalar variable) in the define procedure, so that the "_constant_trap"
knows about the type ...
uplevel 1 [list \
trace add variable \
$varName \
write \
[list \
_constant_trap \
[array exists var] \
$value \
] \
]
3. on arrays there are two different types of write-Access:
- the creation of elements
(to be catched by a write-trace directly onto the array)
- the change of elements
(to be catched by a write-trace directly onto the array element)
But ... so much about that. Much fun!
Best Regards,
Martin Lemburg
----
Thanks. I'll have to look into it. Thanks for the warning on where
my current method was lacking.
Andy