proc
Commandproc procname arglist body
proc
creates a Tcl command in the global
namespace
incr
command. Optional parameters have
a default value that is used when the actual parameter is not
specified. Tcl allows your own proc
s 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.
list
and concat
. You can write Tcl
proc
s 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
return
Commandproc
. You can return a value from a
proc
at an arbitrary point with return
.
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] }
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 } }
eval
Commandeval
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