Data Paradigms in TCL: Associative Arrays vs Dictionaries
Working with TCL for a while, you have to come to terms with the fact that arrays and dicts aren't just different APIs. They're fundamentally different beasts under the hood.
The Implementation Reality
Associative arrays are TCL's original key-value store, implemented
as hash tables directly in the interpreter. When you write
set arr(key) value, you're
actually creating a variable with a compound name. The interpreter
maintains a separate hash table for each array variable, and
accessing $arr(key) triggers a
hash lookup on that specific table.
Dictionaries came later (TCL 8.5 in 2007) as first-class values. Unlike arrays, a dict is just a string with a specific internal representation: a list of alternating keys and values that gets cached as a hash table when you perform dict operations on it. The key insight is that dicts are values that can be passed around, while arrays are variables that live in specific scopes.
Why This Matters in Practice
Arrays tie you to variable scopes. You can't return an array from
a procedure without using
upvar or
global to work around the
limitation. Arrays also can't be nested without ugly naming tricks
like set arr(outer,inner) value.
# Arrays: scope-bound and flat
proc make_config {} {
# Can't return this directly
set config(host) "localhost"
set config(port) 8080
}
# Dicts: values you can actually use
proc make_config {} {
return [dict create host localhost port 8080]
}
Dicts shine for structured data and functional-style programming.
Need nested data?
dict set config database host localhost
just works. Want to pass complex data between procedures? Dicts
are your friend.
Performance Quirks
Here's the counterintuitive part: arrays can be faster for simple key-value operations because there's no string parsing overhead (everything is a string, except when it's not). But dicts win for complex operations because they can optimize their internal representation and handle nesting efficiently.
Arrays also support pattern matching with
array names pattern, which dicts
can't match without iteration.
When to Use What
Use arrays for:
- Simple key-value stores that stay in one scope
- When you need pattern matching on keys
- Legacy code that expects array semantics
Use dicts for:
- Structured, nested data
- Passing data between procedures
- Modern TCL code that values composability
The real lesson? TCL's "everything is a string" philosophy is surface-level, and it means these data structures evolved different internal optimizations while maintaining the same string-based interface. At FlightAware, we've learned this the hard way. Legacy code is full of arrays that should have been dicts, and newer code sometimes uses dicts where arrays would be simpler. Understanding the implementation helps you pick the right tool and avoid performance traps.