Reputation:
I have a question about variables in namespace of TCL.
I have two .tcl files, a.tcl, b.tcl, I define the same global variable in these two files, for example:
a.tcl
variable same "hello1"
b.tcl
variable same "hello2"
proc use {} {
puts same
}
but in b.tcl, I try to define a proc to use the variable "same
", is it a conflicts? which same is used in proc use()?
Upvotes: 2
Views: 10211
Reputation: 113876
Forget about the two files for a moment. Lets assume you just have a single file and the content is:
variable x hello ;# this is a global variable.
proc use {} {
puts $x
}
This should result in an error that says something like $x
is undefined. Why? Because Tcl, unlike C, doesn't import anything into a function that you don't ask it to. Let me say that again: tcl procs doesn't see global or namespace variables that you don't tell it to see.
So, to import global variables the traditional way is to use the global
command:
variable x hello
proc use {} {
global x ;# import $x into this proc
puts $x
}
this should work.
With namespaces of course the word global
doesn't make sense so the variable
command was created to allow procs defined in a namespace to see namespaced variables:
namespace eval foo {
variable x hello
proc use {} {
variable x ;# import $x into this proc
puts $x
}
}
There is also another way to import global and namespaced variables without explicitly using either global
or variable
: just specify the full namespace. The global namespace is simply ::
so the following also works:
variable x hello
proc use {} {
puts $::x
}
and of course:
namespace eval foo {
variable x hello
proc use {} {
puts $foo::x
}
}
Upvotes: 1
Reputation: 16262
It appears from your question (and comments to Donal) that you believe that files have anything to do with namespaces. This thought is incorrect.
a.tcl
variable same "hello a" ;# global namespace
b.tcl
variable same "hello b" ;# global namespace
proc use {} {
variable same ;# reads from the global namespace
puts $same ;# will puts "hello a" or "hello b" depending on whether
;# a.tcl is sourced after b.tcl or not
}
c.tcl
namespace eval ::not_the_global {
variable same "hello c" ;# a different namespace, and a different variable than
;# the one from the previous two files
}
d.tcl
namespace eval ::not_the_global {
proc use {} { ;# a different use proc from the one in b.tcl
variable same ;# the variable defined in this namespace in c.tcl
puts $same ;# will output "hello c" no matter is a.tcl or b.tcl
;# were sourced
}
}
The moral of the story being that the file that code is in is irrelevant, to namespaces or anything else. For a command or variable to be in a separate namespace, it must explicitly be placed in there.
Upvotes: 4
Reputation: 137557
The use
procedure will be in the same namespace as the same
variable (which file the code is in is 100% orthogonal to which namespace it creates commands and variables in). However, the body of use
will not have access to the variables of the namespace by default because all procedure-declared variables are local variables by default. This means that to get access to same
, you should bring it into scope with variable
, probably without the value-initialization argument:
proc use {} {
variable same
puts $same
}
You could also use the fully-qualified name of the variable directly, but that tends to be slower (especially in a loop).
Before you ask, I'd expect the above code to cause use
to print either “hello1” or “hello2”, depending on which order a.tcl and b.tcl are source
d. Any namespacing has to be done explicitly through a namespace eval ::someNsName { ...script... }
. You'd probably put such a thing around the rest of the contents of each of your script files. It's usually considered bad form to write code that depends excessively on the order you source files, mostly because it tends to be quite a lot more difficult to debug…
Upvotes: 3