Variables and Types in Tcl
Learn how Tcl handles variables, its string-based type system, type conversions, and the everything-is-a-string philosophy in practice
Tcl’s approach to variables is unlike almost any other mainstream language. Rooted in the design philosophy that everything is a string, Tcl has no type declarations, no type keywords, and no compile-time type checks. A variable is simply a name bound to a string value, and the interpreter decides how to interpret that string based on the command using it.
This doesn’t mean Tcl is slow or imprecise. Modern Tcl interpreters keep an internal “dual representation” — a value can be cached as both a string and a more efficient form (integer, list, dict) at the same time, transparent to the programmer. From your code’s perspective, however, every value is conceptually a string.
In this tutorial you’ll see how to create variables with set, work with Tcl’s logical “types” (numbers, strings, lists, dictionaries, booleans), perform conversions, and use constants and namespaces. Because Tcl is a dynamic, string-based language, the focus is on what commands do with values rather than what type a variable was “declared” as.
Variable Assignment with set
Tcl has no = assignment operator. The set command both creates and updates variables, and $name retrieves a value.
Create a file named variables.tcl:
| |
Notice that strings, integers, and floats all use the same set syntax. There is no syntactic difference between assigning a number and assigning a string — both are just strings as far as Tcl is concerned. The info exists command tests whether a variable is currently bound.
Logical Types and Their Commands
Although every value is a string, Tcl commands interpret values as numbers, booleans, lists, or dictionaries depending on context. The classifications below are conventions enforced by commands, not type declarations.
Create a file named types.tcl:
| |
Key observation: string is integer and string is double let you classify a value at runtime. Lists are simply strings whose words are separated by whitespace — {apple banana cherry} is both a string and a three-element list, depending on which command consumes it.
Conversions and the expr Command
Because everything is a string, “type conversion” usually means asking a command to interpret a string in a particular way. The expr command is Tcl’s mathematical evaluator, and format / scan are the printf/scanf-style converters.
Create a file named conversions.tcl:
| |
The expression "3.14" * 1.0 shows the philosophy clearly: a quoted string can participate in arithmetic, because expr reads its argument as a math expression and re-parses the string as a number. If the string isn’t a valid number, you get an error at runtime — there’s no compile-time check.
Constants, Scope, and Namespaces
Tcl has no const keyword, but you can simulate immutability with a procedure or with namespace conventions. Variables in Tcl are local to a procedure by default; outside of any procedure, they live in the global namespace.
Create a file named scope.tcl:
| |
Tcl’s scoping is lexical inside procedures, dynamic-feeling outside. A procedure cannot see global variables unless you explicitly say global name or reference them with their fully-qualified name (e.g., ::greeting). Namespaces let you group related variables and procedures, and act as a lightweight stand-in for modules.
Running with Docker
| |
Expected Output
Output from variables.tcl:
count = 10
price = 19.95
name = Ada
message = Tcl is "fun"
set returns: 10
count = 42 (after reassignment)
temp exists? 0
Output from types.tcl:
Integer (decimal): 42
Integer (hex): 0xFF -> 255
Negative: -7
Float: 3.14159
Scientific: 6.022e23
i is integer? 1
pi is integer? 0
pi is double? 1
Length of greeting: 5
Upper: HELLO
Quoted literal: This {keeps} braces literal
yes -> truthy
zero -> falsy
Fruits: apple banana cherry
Length: 3
First: apple
After append: apple banana cherry date
Name: Grace
Age: 85
Updated: 86
Output from conversions.tcl:
string "123" -> integer 123 (1)
string "3.14" -> double 3.14 (1)
Decimal: 255
Hex: 0xff
Octal: 0377
Binary: 11111111
Padded: 00255
Float: 36.429
Parsed age: 42
3 + 2.5 = 5.5 (now a double)
Split list: red green blue (length 3)
Rejoined: red | green | blue
Output from scope.tcl:
Inside proc: Hello
Local: Local hello
Global: Hello
Area of r=5: 78.53981633974475
PI = 3.14159265358979
MAX = 100
Safely tried to unset a missing variable.
Key Concepts
set name valueis the only assignment — there is no=operator, and the same command both creates and updates variables.- Everything is a string — numbers, booleans, lists, and dictionaries are all stored as strings; commands interpret them according to their needs.
- No type declarations — Tcl is dynamic and string-based. Validate at runtime with
string is integer,string is double,string is boolean, etc. expris the math gateway — arithmetic and comparisons requireexpr, which parses its argument as a numeric expression. Always brace expressions:expr {$a + $b}.- Lists are just whitespace-separated strings — use
llength,lindex,lappend,split, andjointo manipulate them; no separate “array literal” syntax exists. - Dictionaries (since Tcl 8.5) provide key/value storage via the
dictcommand family while still being interchangeable with strings. - Scope is local by default in procedures — use
globalor fully qualified names like::varorns::varto reach outside variables. - Use
namespace evalfor pseudo-constants — Tcl has noconst, but namespaces let you group related immutable values and reference them with::ns::name.
Running Today
All examples can be run using Docker:
docker pull efrecon/tcl:latest
Comments
Loading comments...
Leave a Comment