Namespaces for Procedures - 2024.1 English

Vivado Design Suite User Guide: Using Tcl Scripting (UG894)

Document ID
UG894
Release Date
2024-05-30
Version
2024.1 English

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:

  1. The namespace is defined with the command:
    namespace eval <name> { … }
    
  2. Line 1 declares the namespace, foo and line 29 is the closing curly bracket of the namespace definition.
  3. 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 the set command to declare variables inside a namespace as it confuses the Tcl interpreter in the case the same variable name exists in the global namespace.
  4. 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 example foo::).

    Lines 9 and 16: push and pop are created inside the namespace definition

  5. 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.
  6. Lines 10-11, 17-18, 32-33: Procedures refer to variables created inside the namespace using the keyword variable.
  7. A procedure created inside a namespace can be accessed with the full namespace qualifier, for example foo::push, foo::pop and foo::dump. From within the namespace itself, the namespace qualifier is not needed when referring to procedures from the same namespace. For instance, if the procedure dump needs to call push, it does not need to specify foo::push, but just push.
  8. 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"