| Author |
Setting namespace variables
|
|
| graeme.pietersz@gmail.com 2005-10-19, 3:57 am |
| Can someone please explain to me why this happens?
% set a 10
10
% namespace eval ::n1 {set b $a}
10
% set ::n1::b
10
% namespace eval ::n1 {set a $a}
10
% set ::n1::a
can't read "::n1::a": no such variable
% namespace eval ::n1 {set c 10}
10
% set ::n1::c
10
% namespace eval ::n1 {set a 10}
10
% set ::n1::a
can't read "::n1::a": no such variable
%
I had expected to have ::n1::a set to 10 (both times)
| |
| suchenwi 2005-10-19, 3:57 am |
| This is the namespace resolution problem - "Dangers of creative
writing", http://wiki.tcl.tk/1030 . The short answer is: use [variable]
to set or declare variables in namespaces - or full paths:
namespace eval n1 {variable foo 42}
or
set ::n1::foo 42
Note that variables in namespaces are global too, so the same drawbacks
apply. Use local variables wherever possible - it's safer and faster :)
graeme.pietersz@gmail.com schrieb:
> Can someone please explain to me why this happens?
>
> % set a 10
> 10
This sets a global variable (in namespace ::).
> % namespace eval ::n1 {set b $a}
> 10
> % set ::n1::b
> 10
This creates a variable in namespace n1.
> % namespace eval ::n1 {set a $a}
> 10
This finds there is a global "a", so it uses that...
> % set ::n1::a
> can't read "::n1::a": no such variable
....and does not create one in n1.
> % namespace eval ::n1 {set c 10}
> 10
> % set ::n1::c
> 10
Like "b" above.
> % namespace eval ::n1 {set a 10}
> 10
> % set ::n1::a
> can't read "::n1::a": no such variable
> %
>
> I had expected to have ::n1::a set to 10 (both times)
| |
| graeme.pietersz@gmail.com 2005-10-19, 7:59 am |
| suchenwi wrote:
> This is the namespace resolution problem - "Dangers of creative
> writing", http://wiki.tcl.tk/1030 . The short answer is: use [variable]
> to set or declare variables in namespaces - or full paths:
Thanks, that helped a lot. Between your explanation and the wiki link
(which I had completely failed to find although I did try!) I have (I
think) got it.
I will declare namespace variables in future.
>
> namespace eval n1 {variable foo 42}
> or
> set ::n1::foo 42
>
> Note that variables in namespaces are global too, so the same drawbacks
> apply. Use local variables wherever possible - it's safer and faster :)
>
I have been trying to think of a way to avoid using namespaces. The
problem I have is a proc calling another proc which calls another proc
etc and the last proc needs to read and set values in the first. Using
a namespace looked neater than passing all the values needed back and
forth or using upvar.
| |
| Ulrich Schöbel 2005-10-19, 7:59 am |
| Hi,
what about using an array, either a global or a namespaced one,
for this purpose? You only need to declare one variable and then
use the index as kind of a variable name.
Best regards
Ulrich
In article <1129713810.766036.248620@o13g2000cwo.googlegroups.com>,
"graeme.pietersz@gmail.com" <graeme.pietersz@gmail.com> writes:
>
> I have been trying to think of a way to avoid using namespaces. The
> problem I have is a proc calling another proc which calls another proc
> etc and the last proc needs to read and set values in the first. Using
> a namespace looked neater than passing all the values needed back and
> forth or using upvar.
>
| |
| Donald Arseneau 2005-10-19, 7:59 am |
| "graeme.pietersz@gmail.com" <graeme.pietersz@gmail.com> writes:
> I have been trying to think of a way to avoid using namespaces. The
> problem I have is a proc calling another proc which calls another proc
> etc and the last proc needs to read and set values in the first. Using
> a namespace looked neater than passing all the values needed back and
> forth or using upvar.
A namespace looks right for that.
Furthermore, you won't have accidental collisions with global variables
when you are in a proc.
--
Donald Arseneau asnd@triumf.ca
| |
| graeme.pietersz@gmail.com 2005-10-24, 7:57 am |
| There is a problem with doing what I was trying to do: if the proc
exits without deleting the namespace it is not cleaned up like local
variables are. So one can end up with variables from a previous run of
the proc still in existence (if you use the same namespace name) or a
memory leak (if you generate a new namespace name each time). It worked
but became quite messy (wrapping everything up in a catch and deleting
the namespace if there was an exception for example).
I decided to take the advice I got and attempt to only use local
variables. My eventual solution was to pass the absolute level of the
proc (from [info level]) to each proc it calls. This is then passed
down the line. Then each proc upvars what it needs and only what it
needs. This is probably an obvious approach to seasoned TCLers but was
not to me. I am sure this is an obvious to many people who read this,
but I think it worth mentioning for the benefit of others like me.
| |
| suchenwi 2005-10-24, 7:57 am |
| Local variables in procs are
- safer, because they are discarded once the proc is left, and can
cause no side-effects
- faster, because they are created in the bytecode stackframe and
addressed by integer pointer, instead of requiring hash-table lookup by
name
Of course, when you need side-effects, say for stateful objects, or run
in global scope (e.g. Tk bindings), you still need global or namespaced
variables. But in very many cases, intermediate variables are best when
local :)
| |
| Shaun Deacon 2005-10-24, 9:57 pm |
| That makes sense...thanks for the explanation.
regards,
Shaun
|
|
|
|