A procedure is a routine associated with a name that can be used as the first word in a command. proc creates a new procedure, and so do the C functions Tcl_CreateObjCommand() and friends. info commands provides a list of available procedures, and info procs provides a list of available procedures that were created by proc.

See Also

Creating Commands
Enumerates and compares the procedures that create procedures.
Lambda in Tcl
Unnamed/anonymous procedures.
Local procedures
A discussion on limiting the lifespan of a procedure inside another procedure.
Printing proc sequence
A mechanism to trace procedure calls.
Procedure calling timed
Timing procedure calls.
Runtime creation of procs
Wrapping a procedure
Wrap a procedure and call the original, which is stored in $next, at any time
wrapping commands
Various approaches to wrapping procedures.


A procedure is located in a namespace, and can only be found when that namespace is in the resolution path. Whereas as a script is evaluated, a procedure is called. When a procedure is called, a new level is created to hold the variables local to that call, and the namespce of the procedure is the current namespace during the call. Arguments to the procedure become variables at the new level. See global or variable or upvar on how to "import" variables from upper scopes.

A procedure is like a function in that it always returns a value. When the purpose of a procedure is only to produce a side effect, its value is usually the empty string. If there is no explicit return, then the value of the last command is the value of the procedure.

A Procedure Always Has a Name

When a procedure is created from within the body of another procedure, it is bound to the given name in a namespace, remains, even after evaluation at the current level has completed, until it is deleted or its namespace is deleted. There is no way to create a "local" procedure at the current level.

namespace eval foo {
    proc one {} {
        puts -nonewline {Eat }
        proc two {} {
            puts -nonewline {more }
            proc three {} {
                puts chicken.


The Empty Name

AMG PYK: The name of a procedure can even be the empty string, {}, but this has a weird interaction with rename and the way we abuse it for deleting procs.

proc {} {} {
    puts "my name is [info level 0]"

{} ;# -> my name is {}
rename {} {}
catch {{}} msg einfo
puts hello
puts $msg ;# -> invalid command name ""

Also strange: you can create a proc named by the empty string, {}, but you can't use rename to move it.

DKF: You can, but only by renaming to a fully-qualified name, like ::.

Illegal Names

Except to separate namespace parts the namespace separator string, ::, cannot occur in the name of a procedure. This is considered an unfortunate development by some Tcl programmers: If the notation for a procedure name was a list, it would have remained possible to give a procedure any name at all.

See also CMcC's comments in the Tcl Chatroom, 2014-11-28.

Naming Hacks

Almost any string is potentially valid proc name.

RS: "Any string" includes things that look like array elements (but aren't), with which you can emulate "arrays of function pointers":

% proc f(1) {} {puts hello}
% proc f(2) {} {puts world}
% proc f(3) {} {puts again}
% for {set i 1} {$i<=3} {incr i} {f($i)}

And a certain introspection is possible too:

info proc f(*) => f(1) f(2) f(3)

Update 2002-11-15: You don't have to stop at simulating - you can just have arrays of function pointers!

A procedure name that starts with a hash character # can be called by somehow ensuring the # isn't the first character:

proc #test {} {puts [lindex [info level 0] 0]}
\#test ;# -> #test
{#test} ;# -> #test
\x23test;# -> #test
[namespace current]::#test ;# -> ::::#test

Remember that comments are detected prior to the evaluation of a script. # has no importance when commands are being evaluated.

Page Authors