Procedures

The proc Command

proc procname arglist body

Optional Paramaters (Default Values)

Many Tcl commands have optional parameters, such as the increment parameter to the incr command. Optional parameters have a default value that is used when the actual parameter is not specified. Tcl allows your own procs to have optional parameters too.

All optional parameters must be the last parameters to the proc (except for args; see below). This is to prevent ambiguity.

Optional parameters are specified as pairs of formal parameter names and default values in the arglist.

Variable Numbers of Parameters

Many Tcl commands take a variable number of arguments, such as list and concat. You can write Tcl procs that take a variable number of arguments as well by using the special formal parameter name args, which must be the very last parameter.

Within the procedure body, args is bound to a list of values, which are the parameters to the function.

Note that a procedure can take a variable number of remaining arguments; this can often be used to simplify your code. Compare these two procedures:

proc increment-by {args} {
    if {[llength $args] < 1} {
        error "not enough args"
    }
    set inc [lindex $args 0]
    set result {}
    foreach el [lrange $args 1 end] {
        lappend result [expr $el + $inc]
    }
    return $result
}
proc increment-by {inc args} {
    set result {}
    foreach el $args {
        lappend result [expr $el + $inc]
    }
    return $result
}
increment-by 200 1 2 3 4
=> 201 202 203 204

The return Command

The value of a Tcl command is the value of the last Tcl command executed in the proc. You can return a value from a proc at an arbitrary point with return.

Type Signatures

Variable Scope

Tcl has unusual scoping rules. By default, all variables referenced in a proc are local to the procedure. To reference global variables, you must explicitly declare them with the global command. This is the opposite of C, but like C, a free variable can't be used to reference a variable further up the stack.

However, you can explictly bind a variable name to a variable anywhere in the call stack with the upvar command. This allows you to implement call by name for parameters which are variables.

While upvar gives you the power to link to any variable in the call stack, in general you should restrict its use to its default form, which references a variable one level up. This is not a rule which can't be broken, but if you break it you should have a good reason. It's also okay to refer to global variables, but the global command already does that for you.

proc my-incr {var {inc 1}} {
    upvar $var v
    set v [expr $v + $inc]
}

Manipulating Arrays

upvar is the tool you need to manipulate arrays.
proc inc-array {arr {inc 1}} {
    upvar $arr a
    foreach n [array names a] {
        incr a($n) $inc
    }
}

The eval Command

eval is the Tc interpreter itself. It takes a Tcl script as a string, passes it to the interpreter for evaluation, and returns the result. In fact, eval takes any number of string arguments and concatenates them together into a single string with whitespace separating the arguments before evaluation.

eval is useful for evaluating Tcl scripts passed by name. Consider this procedure that applies a Tcl script to a value:

proc apply {script value} {
    $script $value
}
Does it work? Sometimes:
proc I x {set x}
apply I foo
=> foo
apply {K 12} foo
Error: invalid command name "K 12"
The problem is that Tcl only does one level of evaluation: it expands $script to K 12 and $value to foo, but the arguments are already boxed, so Tcl then gets an error looking for a command named K 12. This behavior is very simple and easy to understand, and so is usually what you want. But not in this case. eval is meant to solve precisely these problems.
proc apply {script value} {
    eval $script $value
}
apply {K 12} foo
=> 12
apply {expr 1 +} foo
Error: syntax error in expression "1 + foo"
apply {expr 1 +} 567
=> 568

Keith Waclena
The University of Chicago Library
This page last updated: Tue Aug 2 18:20:44 CDT 1994
This page was generated from Extended HTML by xhtml.