Synopsis edit
- proc name arguments body
Documentation edit
See Also edit
- apply
- command
- corp
- Generate a script to reproduce a procedure.
- Creating Commands
- Enumerates and compares the commands which create commands:
- lego proc manipulation
- A sort of proc templating facility.
- Local procedures
- A discussion on limiting the lifespan of a proc inside another procedure.
- lproc
- Like proc but the body is a list of lists.
- overloading proc
- Guarded proc
- Lambda in Tcl
- Un-named/anonymous procedures.
- Steps towards functional programming
- Jimulation
- An overloaded proc that also takes a set of static variables.
- Printing proc sequence
- A mechanism to trace what procs are called.
- Procedure calling timed
- Timing proc calls.
- proc alias
- How to make an alias for a procedure
- Procs as data structures
- Procs as objects
- Runtime creation of procs
- scope
- Simple proc tracing
- mkproc
- If we had no proc
- saving all procedures
- Wrapping a procedure
- Wrap a procedure and call the original, which is stored in $next, at any time
- wrapping commands
- Various approaches to wrapping commands
Description edit
proc creates a new Tcl procedure named name, replacing any existing command having the same name. Whenever the new command is evaluated, the contents of body are evaluated in the namespace where the procedure is defined, at a new level where the only accessible variables are those created to hold the arguments passed to the procedure. global, upvar, namespace upvar, and variable can be used to link in namespace variables and variables at other levels. Similarly, uplevel and namespace eval can be used to evaluate scripts in namespaces or at other levels. Command names in body are resolved as described in name resolution.When name is unqualified (does not include the names of any containing namespaces), the new command is created in the current namespace. If name includes any namespace qualifiers, the command is created in the specified namespace. A partially-qualified name is resolved relative to the current namespace.arguments is a list, possibly empty, of arguments to the procedure. If any list item itself contains two items, the second item becomes the default value for that argument. When the command is evaluated, each actual argument is stored in the variable named by the argument.Any argument that follows an argument having a default value must itself have a default value.A procedure may accept a variable number of arguments by naming the last argument 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 command name. Thus, list can be implemented as:
proc List args {set args}An argument named args only has this special behaviour if it is the last argument.The value of a procedure is the value of the last command evaluated in body . return can be used to end a procedure at some point other than the last command in body.When a procedure is renamed, any existing procedure by that name is overwritten, and 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 by the interpreter, a command created by proc does not extend Tcl.
Procedure Results edit
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 return value of the proc, and the others using upvared variables.
- Return all results in variables.
foreach {first second third} [makeThreeResults $input] breakLarry Smith: I still think let is more readable:
let a b c @= 1 2 3DKF: Use lassign from 8.5 onwards.
lassign [makeThreeResults $input] first second third
Procs Always Bind to a Namespace edit
Even when they are created from with the body of another function, procs are bound to the current namespace, and exist for the life of that namespace, or until they are deleted:namespace eval foo { proc one {} { puts -nonewline {Eat } proc two {} { puts -nonewline {more } proc three {} { puts chicken. } } } } foo::one foo::two foo::three
Default Values edit
- Selected Topics in Tcl/Tk, Changhai Lu
- a a discussion of Tcl proc's default argument capability.
schlenk 2004-08-03: Here's a little proc 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 "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;# -> 0HaO 2011-03-16: The above is very good. I have seen an in-proc 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 Proc edit
proc foo {args} { puts "proc = [lindex [info level 0] 0]" }See: info level
Clobbering Existing Procedures edit
The name of a procedure may be any string, including the empty string.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 each widget, there exists a command whose name is the path of the widget. Defining a proc of the name of any existing widget is going to result (in the very best of cases) potentially strange behavior and, in worse cases, catastrophe.
Procedure Compilation edit
- bytecode
- the main page on the subject
- Proc to bytecodes: when, how does it happen
The Empty Name edit
AMG PYK: The proc name 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 "" but you can't use rename to do it.DKF: You can, but only by renaming to a fully-qualified name, like ::.
Illegal Names edit
As CMcC noted in the Tcl Chatroom, 2014-11-28, the name of a procedure in any namespace other than the global namespace may not begin with :. This is a consequence of designating :: as the namespace delimiter, which is considered an unfortunate development by some Tcl programmers who would have rather seen lists used for that purpose.Pass by Reference edit
- Implicit upvar
- RS's take on the matter
- deref
- Larry Smith's approach
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
Naming Hacks edit
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 againAnd 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 proc 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 ;# -> ::::#testRemember that comments are detected prior to the evaluation of a script. # has no importance when commands are being evaluated.
Misc edit
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