Organizing Code with Namespaces
As a Tcl program grows past a single script, procedure and variable names inevitably start to collide - two libraries both defining a proc called init or a variable called config. The namespace command solves this by creating a separate naming context, so namespace eval Db {proc init {} {...}} defines a procedure reachable as ::Db::init without touching any global init that might already exist. Namespaces can nest arbitrarily deep with :: as the separator, mirroring how a filesystem path separates directories, and every namespace has its own variable table distinct from the global scope.
Cricket analogy: Namespaces preventing name collisions are like two different domestic leagues both having a team called 'Strikers' - the full names 'Mumbai Strikers' and 'Melbourne Strikers' disambiguate them just as ::Db::init differs from ::Ui::init.
Defining and Accessing Namespace Contents
namespace eval Db { variable connCount 0; proc init {} { variable connCount; incr connCount } } creates both a namespace variable and a procedure inside it in one call; from outside, the procedure is invoked as Db::init (Tcl resolves the leading :: implicitly if the namespace already exists) and the variable is read with set ::Db::connCount or, from another proc inside the same namespace, with variable connCount to import it into local scope. namespace export and namespace import let one namespace selectively expose specific procedure names to another, avoiding the need to always type the fully qualified path.
Cricket analogy: namespace export selectively exposing procedure names is like a franchise releasing only its official injury-list update to the media while keeping internal training-ground notes private.
namespace eval ::Db {
variable connCount 0
namespace export connect init
proc init {} {
variable connCount
set connCount 0
puts "Db initialized"
}
proc connect {name} {
variable connCount
incr connCount
puts "connected to $name (total: $connCount)"
}
}
Db::init
Db::connect "primary"
Db::connect "replica"
# Selectively bring exported commands into the current namespace
namespace import ::Db::connect
connect "analytics"Ensembles and namespace current
namespace ensemble create turns a namespace into a single dispatch command, so instead of calling Db::connect and Db::init separately, callers can write db connect ... and db init ... through one unified command name, similar to how the built-in string or dict commands dispatch to subcommands. Inside any procedure, namespace current returns the fully qualified name of the namespace it's executing in, which is useful for self-referential logic like registering a callback that must call back into the same namespace regardless of where it was originally invoked from.
Cricket analogy: namespace ensemble create unifying connect and init under one 'db' command is like a stadium's single help desk routing ticketing, catering, and parking queries instead of forcing fans to find three separate counters.
Because Tcl's variable command inside a proc only creates a local alias to a namespace variable - it doesn't copy its value - two procs in the same namespace that both call 'variable connCount' are reading and writing the exact same underlying storage, just like two global-scope references to the same variable.
namespace eval always executes its body in the target namespace's context, but a nested proc's own local variables still require an explicit 'variable' declaration to reach namespace-scoped variables - simply referencing $connCount inside a proc without declaring it first will resolve to an undefined local variable, not the namespace one, and raise an error.
- namespace eval creates an isolated scope for procedures and variables, avoiding global name collisions.
- :: separates nested namespace levels, similar to a filesystem path.
- Fully qualified names like ::Db::init unambiguously reference a specific namespace's contents.
- namespace export and namespace import selectively expose commands between namespaces.
- The variable command inside a proc creates a local alias to the same underlying namespace storage.
- namespace ensemble create groups related procedures under one dispatching command name.
- namespace current returns the fully qualified name of the namespace currently executing.
Practice what you learned
1. What is the primary purpose of Tcl's namespace command?
2. What separator is used between nested namespace levels?
3. What does the variable command do when called inside a proc defined within a namespace?
4. What does namespace ensemble create allow you to do?
5. What happens if a proc references $connCount without first declaring 'variable connCount', when connCount is a namespace variable?
Was this page helpful?
You May Also Like
Error Handling with catch and try
How Tcl scripts detect, inspect, and recover from runtime errors using the catch command and the more structured try/on/finally syntax.
Tcl Object-Orientation with TclOO
How to define classes, objects, methods, and inheritance in Tcl using the built-in TclOO framework (oo::class, oo::define, oo::copy).
File I/O in Tcl
Reading, writing, and managing files and channels in Tcl using open, read, gets, puts, and the channel configuration commands.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics