This Is How I Glyph – Tcl Namespaces (Part 1)

This is the first in a series of posts about the Tcl namespace command. Each subsequent post will cover more complex uses of namespaces. While this topic is strictly related to Tcl only, it could help you when developing more complex Glyph scripts.

What is a Namespace?

In its simplest usage, a namespace allows you to define and manipulate a collection of Tcl variables and procs under the “protection” of a named context. The variables and procs defined in one namespace will never have a name conflict with those defined in another namespace. For instance, you can define a variable named x in multiple namespaces. Each x can have a different value.

While namespaces are very useful to isolate different parts of a complex application, they are exceptionally powerful when implementing a Tcl/Glyph library. Placing all the library’s procs and state variables in a namespace will virtually eliminate the possibility of naming conflicts in the scripts that source your library.

A Simple Example

The namespace named ns is defined below using the namespace eval subcommand. The ns namespace defines the variables i and s and the procs printI, printS, and printIS.

namespace eval ns {
  variable i 3
  variable s "Hello World!"

  proc printI { } {
    variable i
    puts "ns::printI / i=$i"
  }

  proc printS { } {
    variable s
    puts "ns::printS / s=$s"
  }
}

proc ns::printIS { } {
  variable i
  variable s
  puts "ns::printIS / i=$i s=$s"
}

The variable i is initialized to the value 3 and the variable s initialized to the value “Hello World!”. Specifying an initial value is optional. However, I would strongly suggest that all namespace variables are initialized to a meaningful value.

The first two procs, printI and printS, are defined within the body of the namespace eval subcommand. As such, these procs are implicitly part of namespace ns and do not need any namespace decorations. However, the third proc, printIS, is defined outside of the namespace body. In this case, the proc name is prefixed with ns:: to signify the name of its enclosing namespace.

The choice of whether to define a namespace proc inside or outside of the namespace body is a stylistic one. Both methods achieve the same result. The only requirement is that the namespace eval must be completed before any procs are defined outside of that namespace.

As shown in the code, the namespace procs can access the namespace variables by first importing them into the proc using the variable command. For instance, printI gains access to the namespace variable i by importing it using variable i.

Using a Namespace

Once a namespace is defined, you can access its variables and procs in your Tcl or Glyph script by prefixing their usage with the namespace’s name and the :: delimiter as demonstrated in the code below.

# call namespace procs
ns::printI
ns::printS
ns::printIS

# access namespace vars directly
puts "ns::i = $ns::i"
puts "ns::s = $ns::s"
set ns::s {Fly by Night}
puts "ns::s = $ns::s"

# Output:
# ns::printI / i=3
# ns::printS / s=Hello World!
# ns::printIS / i=3 s=Hello World!
# ns::i = 3
# ns::s = Hello World!
# ns::s = Fly by Night

For those readers familiar with object oriented languages, you may have noticed there are no access control keywords such as private, protected, or public. That is because the Tcl language does not support access control to namespace procs and variables. If a variable or proc is defined, it can be accessed or modified. So, your only recourse is to comment the namespace code accordingly and trust that users will use the namespace as documented and leave private variables and procs alone.

Preventing Conflicts

As I mentioned above, namespaces prevent naming conflicts. The code below demonstrates that distinct global variables and procs with the same names as used within namespace ns can be created without conflict.

# global vars
set i 99
set s {Moving Pictures}

# global proc
proc printIS { } {
  global i
  global s
  puts "global printIS / i=$i s=$s"
}

printIS
puts "i = $i"
puts "s = $s"

# Output:
# global printIS / i=99 s=Moving Pictures
# i = 99
# s = Moving Pictures

In addition, another distinct set of procs and variables can be created by copying and pasting the ns namespace code and changing the copy’s name from ns to something else like ns2 as shown below. In this case, the procs and variables would be accessed as ns2::i, ns2::printI, etc.

namespace eval ns2 {
  variable i 6
  variable s "Snakes & Arrows"

  proc printI { } {
    variable i
    puts "ns2::printI / i=$i"
  }

  proc printS { } {
    variable s
    puts "ns2::printS / s=$s"
  }
}

proc ns2::printIS { } {
  variable i
  variable s
  puts "ns2::printIS / i=$i s=$s"
}

Glyph2 and Namespaces

You may not realize it, but you have already been using namespaces. For instance, Glyph2 itself uses both the pw and pwu namespaces. When you use pw::Grid or pwu::Vector2 in a script, you are using namespaces. In addition, Tcl itself places all top-level variables and procs into the global namespace (named ::).

When a proc needs to access a global variable, you usually declare it inside the proc’s body using the global command. You can also access the global variable using the :: global namespace decorator. The following code demonstrates different ways to access variables defined in the global namespace.

set globalVar 0

proc incrA { delta } {
  # Make the global variable globalVar visible in this proc
  global globalVar
  # Increment the global variable's value
  return [incr globalVar $delta]
}

proc incrB { delta } {
  # Access global variable directly using the global
  # namespace prefix
  return [incr ::globalVar $delta]
}

# These two lines print the same thing
puts " \$globalVar = $globalVar"
puts "\$::globalVar = $::globalVar"

# incr globalVar by 3
puts " incrA 3 = [incrA 3]"

# incr globalVar by 5
puts " incrB 5 = [incrB 5]"

# Output
# $globalVar = 0
# $::globalVar = 0
# incrA 3 = 3
# incrB 5 = 8

Until Next Time

This post covered basic creation and usage of Tcl namespaces. I will be covering additional namespace subcommands in future posts. If you want to learn more about namespaces, then take a look at the full Tcl namespace documentation.

This Is How I Glyph – Tcl Namespaces (Part 2) | Another Fine Mesh

About David Garlisch

Illini by birth, Texan by choice.
This entry was posted in Applications, Software. Bookmark the permalink.

2 Responses to This Is How I Glyph – Tcl Namespaces (Part 1)

  1. Pingback: This Is How I Glyph – Tcl Namespaces (Part 2) | Another Fine Mesh

  2. Pingback: This Is How I Glyph – Tcl Namespaces (Part 3) | Another Fine Mesh

Leave a Reply