proc

proc , a built-in procedure, creates a new procedure.

Synopsis

proc name arguments body

Documentation

official reference

See Also

corp
Generate a script to reproduce a procedure.
lego proc manipulation
A sort of procedure templating facility.
lproc
Like proc but the body is a list of lists.
overloading proc
Guarded proc
Steps towards functional programming
Jimulation
Overloads proc to accept a list of static variables.
proc alias
How to make an alias for a procedure
Procs as data structures
Procs as objects
scope
Simple proc tracing
mkproc
If we had no proc
saving all procedures

Description

proc creates a new procedure named name, replacing any existing procedure having the same name. When name is not absolute, i.e. when the first namespace part is not the empty string, the new procedure is created in the current namespace. If name includes any namespace qualifiers, it is resolved relative to the current namespace and the procedure is created in the corresponding namespace.

arguments is a list of zero or more argument specifications. Each specification where the first item is the name of the variable to store the corresponding argument to, and the second item, if provided, is the default value of the variable. Any argument that follows an argument having a default value must itself have a default value.

When the new procedure is called, each argument to the call is stored in the specified variable at the new level for the call, and body is evaluated at that level. global, upvar, namespace upvar, and variable can be used to link local variables to namespace variables and variables at higher levels. Similarly, uplevel and namespace eval can be used to evaluate scripts in namespaces or at other levels. Procedure names in body are resolved as described in name resolution.

Example:

proc myproc {arg1 arg2} {
    # do something here, e.g.
    puts [list arg1 $arg1 arg2 $arg2]
}

If the last argument specification for a procedure is args, then the procedure accepts a variable number of arguments, which are stored as a list in $args:

proc myvarproc {foo bar args} {
    puts "<$foo> <$bar> <$args>"
}

myvarproc a b c d e
# => <a> <b> <c d e>
myvarproc a b
# => <a> <b> <>

When the command is evaluated all additional words are added to a list which is then assigned to $args. If there are no additional words, $args is empty. If args is the only argument, $args is a list of all the words after the procedure name. Thus, list can be implemented as:

proc List args {set args}

The value of a procedure is the value of the last command evaluated in body . return can be used to end a procedure at an earlier point in body.

When a procedure is overwritten no warning is given. To guard against such an event, see overloading proc with a Guarded proc.

Because body is a script to be evaluated, a procedure created by proc does not extend Tcl.

Procedure Results

Silas 2005-08-18: I think the best way to return multiple values is to use a list. For example:

proc v {} {
    set value1 somevalue
    set value2 anothervalue
    return [list $value1 $value2]
}

arjen told me would be a good idea to use upvar. See (I haven't tested it):

proc v {name1 name2} {
    upvar 1 $name1 n1
    upvar 1 $name2 n2
  
    set n1 1
    set n2 2
}

v N1 N2
puts "$N1 $N2"

RS: The first approach, returning a list of the results, is "cleaner" in the functional programming sense. The upvar approach creates side effects as it changes the value of variables.

Lars H: In real life, which approach is preferable varies quite a lot. There are on the whole at least three possibilities to consider:

  • Return the list of the results.
  • Return one result as the value of the procedure, and the others using upvared variables.
  • Return all results in variables.

Taking apart a list of values returned is sometimes annoyingly cumbersome, but in other cases that list is a good thing to have. Usually it all depends on what you're going to do with the results once you've got them.

One thing that is fairly easy to do using upvared variables is to provide optional results -- provide an optional argument for the name of a variable in which to pass back a result, but if such an argument is not given then don't pass the result back (perhaps avoid computing it altogether).

RS: Taking apart a list is pretty easy with the foreach ... break idiom :)

foreach {first second third} [makeThreeResults $input] break

Larry Smith: I still think let is more readable:

let a b c @= 1 2 3

DKF: Use lassign from 8.5 onwards.

lassign [makeThreeResults $input] first second third

Default Values

Selected Topics in Tcl/Tk , Changhai Lu
A discussion of the default argument feature.

schlenk 2004-08-03: Here's a little procedure to check if defaults were used or actual arguments were present, this can be handy if a default value is used as a don't care token.

proc defaultvalues? {} {
    puts [list hey [info level -1]]
    expr {[llength [info args [lindex [info level -1] 0]]]
                - ([llength [info level -1]]-1)}
}

Trying it out:

proc test {a {b 1} {c 2}} {puts [defaultvalues?]}

test 1 ;# -> 2

test 1 2;# -> 1

test 1 2 3;# -> 0

HaO 2011-03-16: The above is very good. I have seen an in-procedure variant like that:

proc c {a {b {}}} {
    if {2 == [llength [info level 0]]} {
        # code when optional argument b was not passed
    }
}

Doing nonsensical things with default args:

proc defaultargs {{def a} undef} {
    puts [format {def: "%s", undef: "%s"} $def $undef]
}

defaultargs x y ;# -> def: "x", undef: "y"

catch {defaultargs x} msg
puts $msg ;#-> wrong # args: should be "defaultargs ?def? undef"

Determine the Name of the Current Procedure

proc foo args {
    puts "proc = [lindex [info level 0] 0]"
}

See: info level

Clobbering Existing Procedures

When creating a new procedure, no warning is given when it replaces an existing procedure by the same name. If, for example, in a Tk applicaiton, you were to code:

proc . {} {}

you would find that you have destroyed the default toplevel, likely causing the app to exit.

This is because for each widget, there exists a procedure whose name is the path of the widget. Defining a proc having the name of any existing widget has the potential in the very best cases to result in strange behavior and, and in worse cases to be catastrophic.

Procedure Compilation

bytecode
The main page on the subject.
Proc to bytecodes: when, how does it happen

Pass by Reference

Implicit upvar
RS's take on the matter
deref
Larry Smith's approach

DKF 2003-07-16 PYK 2013-09-01: Here's a way to do magic "dereferencing" which C hackers might like...

proc proc2 {name arglist body} {
    set header {}
    foreach a $arglist {
        if {[string first * $a] == 0} {
            append header "upvar 1 \[set $a] [string range $a 1 end];"
        }
    }
    proc $name $arglist $header$body
}

proc2 test {a *b c} {puts "a=$a, b=$b c=$c"}
set quantity 4
test 1 quantity 3 ;# -> a=1, b=4, c=3

Misc

Every set of cards made for any formula will at any future time recalculate that formula with whatever constants may be required. Thus the Analytical Engine will possess a library of its own.

- Charles Babbage, 1864