Functions in Tcl
Learn how to define and call procedures in Tcl - parameters, default values, variable arguments, scope, recursion, and first-class higher-order functions with Docker-ready examples
In Tcl, the unit of reusable code is the procedure, defined with the proc command. True to Tcl’s philosophy that everything is a command, proc doesn’t introduce special “function” syntax—it is itself a command that registers a brand-new command in the interpreter. Once defined, your procedure is called exactly like any built-in command such as puts or set.
Because Tcl is a dynamic, string-based language, procedures are flexible: parameters have no declared types, you can supply default values, and a special args parameter lets a procedure accept any number of arguments. Variables inside a procedure are local by default, which keeps procedures self-contained—but Tcl gives you global and upvar to reach beyond that boundary when you need to.
This tutorial covers defining and calling procedures, passing parameters and returning values, default and variadic arguments, variable scope, recursion, and Tcl’s support for higher-order functions through apply and anonymous lambdas. Since Tcl is multi-paradigm (procedural and functional), we’ll lean into both styles.
Defining and Calling Procedures
A procedure is defined with proc name {parameters} {body}. The result of the procedure is whatever you return—or, if you omit return, the result of the last command in the body.
Create a file named functions.tcl:
| |
The procedure body runs when the command is called, and [add 3 4] uses command substitution to capture the returned value. Note that expr {...} is used for arithmetic—in Tcl, math is not built into the language but performed by the expr command.
Default and Variable Arguments
Tcl supports default parameter values by writing a parameter as a {name value} pair. The special args parameter collects all remaining arguments into a list, giving you variadic procedures.
Create a file named functions_args.tcl:
| |
The ** operator is Tcl’s exponentiation operator. Because exp has a default of 2, calling power 5 squares the base, while power 2 10 overrides the default.
Variable Scope
Variables created inside a procedure are local—they vanish when the procedure returns and never touch the caller’s variables. To work with a global variable, declare it with global. To modify a caller’s variable by reference, use upvar.
Create a file named functions_scope.tcl:
| |
Notice that double receives the name value (not its contents), and upvar 1 binds the local x to the caller’s variable one level up the call stack. Mutating x therefore changes value in place—this is how Tcl procedures modify their arguments.
Recursion
A procedure can call itself, making recursion natural in Tcl. Here are the classic factorial and Fibonacci examples.
Create a file named functions_recursion.tcl:
| |
Each recursive call gets its own local n, so the call stack keeps the intermediate values separate. The nested [expr {...}] calls evaluate the arguments before the outer multiplication or addition runs.
Higher-Order Functions
Tcl can treat procedures as data. You can pass a procedure’s name and invoke it indirectly, or create anonymous functions—lambdas written as a {args body} list—and run them with the apply command.
Create a file named functions_higher_order.tcl:
| |
Because everything in Tcl is a string, inc is just the name of a command that can be stored in a variable and invoked via $fn. The apply command takes a lambda—a two-element list of parameters and body—and runs it on the spot, no name required.
Running with Docker
The efrecon/tcl image’s entrypoint is tclsh, so you pass the script path directly to the container.
| |
If you have Tcl installed locally, run any example with tclsh functions.tcl.
Expected Output
Running functions.tcl:
add 3 4 = 7
Hello, Tcl!
square 5 = 25
Running functions_args.tcl:
power 5 = 25
power 2 10 = 1024
sum 1 2 3 4 = 10
sum (no args) = 0
Running functions_scope.tcl:
inside proc: 99
global still: 0
after two increments: 2
doubled value: 42
Running functions_recursion.tcl:
factorial 5 = 120
factorial 10 = 3628800
first 10 fib: 0 1 1 2 3 5 8 13 21 34
Running functions_higher_order.tcl:
applyTwice inc 5 = 7
apply lambda 7 = 49
map square: 1 4 9 16 25
Key Concepts
procdefines a command — A procedure is just a new command registered in the interpreter; you call it exactly likeputsor any built-in, with no special call syntax.- Implicit return — If you don’t use
return, the value of the body’s last command becomes the procedure’s result. - Arithmetic lives in
expr— Tcl has no built-in math operators in procedure bodies; wrap calculations inexpr {...}(the braces protect the expression from premature substitution and improve performance). - Default and variadic parameters — Write
{name value}for a default, and use the specialargsparameter to gather any number of trailing arguments into a list. - Local by default — Variables set inside a procedure are local; reach globals with
globaland modify a caller’s variables by reference withupvar. - Recursion is natural — Each call gets its own local frame, so self-referential procedures like
factorialandfibwork cleanly. - Procedures are first-class — Store a procedure’s name in a variable and invoke it via
$fn, or write anonymous{params body}lambdas and run them withapply, enabling functional patterns likemap.
Running Today
All examples can be run using Docker:
docker pull efrecon/tcl:latest
Comments
Loading comments...
Leave a Comment