By default, every procedure created inside the Tcl interpreter is created inside the global namespace. A disadvantage of this is potential conflicts with the procedure or variable names when multiple Tcl scripts from different sources are being used. In addition, the global namespace is also being polluted by procedure names that might be only be used by some other procedures and that are not meant to be directly accessed by the user.
Instead of defining all the variables and procedures in the global namespace, Tcl supports the concept of namespace that encompasses variables and procedures inside a more private scope. Namespaces can also be nested, so a namespace can be defined inside another namespace without restriction on the number of levels of scoping. Namespaces add a new syntax to procedure and variable names. A double-colon, ::, separates the namespace name from the variable or procedure name.
Below is an example that illustrates how a namespace is created and how procedures and variables are assigned to the namespace. This example creates a namespace, foo
that reproduces the functionality of a small stack with two public procedures (push
and pop
):
01 namespace eval foo {
02 variable stack [list]
03 variable count 0
04 variable params
05 array set params [list var1 value1 var2 value2 var3 value3]
06
07 namespace export push pop
08
09 proc push { args } {
10 variable stack
11 variable count
12 lappend stack $args
13 incr count
14 }
15
16 proc pop {} {
17 variable stack
18 variable count
19 if {[llength $stack] > 0} {
20 set value [lindex $stack end]
21 set stack [lrange $stack 0 end-1]
22 incr count -1
23 return $value
24 } else {
25 error " no more element in the stack"
26 }
27 }
28
29 }
30
31 proc foo::dump {} {
32 variable stack
33 variable count
34 if {[llength $stack] > 0} {
35 puts " There are $count element(s) in the stack:"
36 foreach element $stack {
37 puts " $element"
38 }
39 return 0
40 } else {
41 error " no element in the stack"
42 }
43 }
44
45 namespace import foo::*
Explanations:
- The namespace is defined with the command:
namespace eval <
name> { … }
- Line 1 declares the namespace,
foo
and line 29 is the closing curly bracket of the namespace definition. - Variables inside the namespace are created with the command
variable
(lines 2-4):variable <varname> ?<varvalue>?
A Tcl array cannot be initialized with the
variable
command. It needs to be created first (line 4) and initialized afterward (line 5).Note: Do not use theset
command to declare variables inside a namespace as it will confuse the Tcl interpreter in the case the same variable name exists in the global namespace. - Procedures can be created directly inside the namespace definition or outside. When a procedure is created within the command,
namespace eval … { … }
, it does not need to have the namespace qualifier in the name (in this examplefoo::
).Lines 9 and 16:
push
andpop
are created inside the namespace definition - Procedures can also be created outside of the namespace definition and added to the namespace by using the full namespace qualifier prepended to the procedure name. In the above example, the procedure
dump
(line 31) is created output of the namespace definition but added to the namespace foo. - Lines 10-11, 17-18, 32-33: Procedures refer to variables created inside the namespace using the keyword
variable
. - A procedure created inside a namespace can be accessed with the full namespace qualifier, for example
foo::push
,foo::pop
andfoo::dump
. From within the namespace itself, the namespace qualifier is not needed when referring to procedures from the same namespace. For instance, if the proceduredump
needs to callpush
, it does not need to specifyfoo::push
, but justpush
. - Line 7: The namespace supports the concept of public and private procedures. Although all the procedures within a namespace can be accessed with the full namespace qualifier, a namespace can specify which of the procedures can be exported outside of the namespace with the command,
namespace export…
. Once a procedure name is exported, it can be imported into the global namespace with the command,namespace import…
(line 45). Doing that enables the procedure to be directly called without having to specify the full namespace qualifier.Here is an example usage of the namespace
foo
:vivado% foo::push This is a test 1 vivado% foo::push {This is another line} 2 vivado% push This is the third line 3 vivado% foo::dump There are 3 element(s) in the stack: This is a test {This is another line} This is the third line 0 vivado% puts "The last element stacked is: [foo::pop]" The last element stacked is: This is the third line vivado% puts "The previous element stacked is: [pop]" The previous element stacked is: {This is another line} vivado% foo::dump There are 1 element(s) in the stack: This is a test 0 vivado% dump invalid command name "dump"