Tcl Procedures

Procedures organize a repetitive group of commands into a logical block and allow for arguments to be parameterized. They improve performance and memory because a procedure’s commands and variables only exist within the scope of the procedure.

This means that variables created inside a procedure only exist while the procedure is executed and are destroyed when the procedure returns.

The proc command is used to define a procedure. There are optional arguments that can be defined for a procedure as values that will be passed to the procedure when the procedure is called. Each parameter becomes a variable in the procedure. The commands contained within the curly braces are run when the procedure is called. The format of a procedure is:
proc name {?arg1? ?arg2? etc…} {body}

After a procedure is defined, it is used just like any other Tcl command. The name of the procedure becomes a new Tcl command name and is called just like any standard Tcl command. In this way, it is also possible to redefine (or undefine) the function of existing Tcl commands.

An example procedure named curve_info that takes curve_reference and color as its arguments:
proc curve_info {curve_reference color} {
   puts "Curve reference = $curve_reference";
   puts "Curve color = $color";
}
curve_info p1w1c1 5;
Curve reference = p1w1c1
Curve color = 5
The name args is a special procedure parameter when you don’t know how many arguments will be used. This is useful when creating a context sensitive menu where multiple items may be passed.
proc node_info {args} {
   foreach node $args {
      puts "Node = $node";
   }
}
node_info node1 node2 node3;
Node reference = node1
Node reference = node2
Node reference = node3
Variables are treated as one argument and don’t require the args parameter.
proc node_info {node_list} {
   foreach node $node_list {
      puts "Node = $node";
   }
}
set node_list "node1 node2 node3";
node_info $node_list;
Node reference = node1
Node reference = node2
Node reference = node3
The return command is used to exit a procedure. This is handy for error control.
proc node_info {args} {
   if {[llength $args] == 0} {
      puts "No nodes are selected";
      return;
   }
   foreach node $args {
      puts "Node = $node";
   }
}
curve_info;
No curves are selected

curve_info node1 node2 node3;
Node = node1
Node = node2
Node = node3
The return command can also be used to assign the results of a procedure to a variable.
proc add_three_numbers {num1 num2 num3} {
   set sum [expr $num1 + $num2 + $num3];
   return $expression;
}
set sum [add_three_numbers 2 4 5];
puts $sum;
11

Procedure names, by default, are defined in the global scope (top level) of a Tcl script. Any variables that are defined outside of a procedure are also part of the global scope and are called global variables. Different namespaces exist for procedure names and global variables so it is possible to have procedures and variables with the same name without issue. It is also possible, and recommended, to use the Tcl namespace facility to manage the scope of procedures and variables.

As mentioned above, all variables defined within a procedure are local to that procedure. This means that, unless otherwise defined, a variable definition only exists, and is only accessible, from within the procedure it is created in.
set element_list "1 2 3 4 5";
proc element_info {} {
   puts $element_list;
   set node_list "10 20 30 40";
   puts $node_list;
}
element_info;
can't read "element_list": no such variable
10 20 30 40

puts $element_list;
1 2 3 4 5

puts $node_list;
can't read "node_list": no such variable
This also allows the programmer to define the same local variable within different procedures without any conflict.
proc node_info_1 {} {
   puts $node_list;
   set node_list "10 20 30 40";
   puts $node_list;
}

proc node_info_2 {} {
   puts $node_list;
   set node_list "10 20 30 40";
   puts $node_list;
}
node_info_1;
can't read "node_list": no such variable
10 20 30 40

node_info_2;
can't read "node_list": no such variable
10 20 30 40

As a general rule, it is good practice to create focused procedures that have specific functions which are modular and reusable. This allows the procedure to perform a specific operation that allows other developers to easily see what function the procedure performs. It also allows procedures to be reused in other scripts that may require similar functions.