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.
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.
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. } } } } foo::one foo::two foo::three
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 ::.
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.
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)} hello world again
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.