- proc name arguments body
Extending proc edit
Redefining an existing proc occurs silently and may result in unexpected errors (or even security breaches) if the proc is not carefully constructed. You can detect this type of error by overloading proc with a Guarded proc.For a discussion on limiting the lifespan of a proc inside another proc, see Local proceduresFor unnamed/anonymous procedures see Lambda in Tcl and Steps towards functional programming.See Jimulation for an overloaded proc that also takes a set of static variables.Arguments edit
It is not specifically documented in the man page, but a proc's arguments must be defined to occur in the following sequence:- zero or more undefaulted arguments
- zero or more defaulted arguments
- optionally the special literal args argument; its appearance as the last argument results in the possible collection of additional arguments into a list called args.
proc defaultargs {{def a} undef} {
puts "def \"$def\", undef \"$undef\""
}
defaultargs x y
->
def "x", undef "y"
catch {defaultargs x} msg
puts $msg
->
wrong # args: should be "defaultargs ?def? undef"See http://www.changhai.org/contents/technology/programming/tcltricks.html for a discussion of Tcl proc's default argument capability.
DKF - 16-Jul-2003 - 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 match {\**} $a]} {
append header "upvar 1 \${$a} [string range $a 1 end];"
}
}
proc $name $arglist $header$body
}Trying it out: % proc2 test {a *b c} {puts "a=$a, b=$b c=$c"}
% test 1 argc 3
a=1, b=0 c=3See also Implicit upvar for RS's take, deref for Larry Smith's.schlenk - 03-Aug-2004 - 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? {} {
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 upper 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
}
}Procedure Compilation edit
See Proc to bytecodes: when, how does it happen. Printing proc sequence implements a mechanism to trace what procs are called. Procedure calling timed discusses timing proc calls.The Empty Name edit
Note that name may be any string. However, note that due to the silent replacement mentioned above, if in a Tk application you were to code: proc . {} {}you will find that you have destroyed the default toplevel, mostly causing the app to exit.This is because each widget created has a proc-equivalent (with the name of the widget) created. 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.AMG: The proc name can even be "", but this has a weird interaction with [rename] and the way we abuse it for deleting procs. % proc "" {} {puts "my name is [info level 1]"}
% ""
my name is {}
% rename "" ""
% ""
empty command name ""That's strange: the no-such-command error message is different than the usual "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 ::.Naming Hacks edit
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!MG You can also define procs with names starting with the hash character (#) which makes them completely uncallable, as the Tcl parser evaluates it as a comment rather than a command. Whether or not there'd be any reason to do so (aside from "commenting out" a particular proc quickly), I'm not really sure, but I thought it was an interesting quirk.Lars H: No, a name starting with a # doesn't render a procedure impossible to call. Consider
% proc #test {} {info level 1}
% \#test
#test
% {#test}
#testRemember that comments are detected before a command is split into words. # has no importance when commands are being evaluated.MG wasn't aware you could do that - I guess my understanding of how and when comments were checked for was a little off. Will have to read into that some more in the future... :)Procedure Results edit
Silas - 18-Aug-2005 - 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
(Non-)Scoping edit
willdye Here's a quick demo of how procs are (normally) declared in the global scope. Feel free to extend this code to also show how namespaces can make procs 'local'. % proc outer {} {puts "If a proc is declared inside another proc, is it local?"
proc middle {} {puts "No. Unlike vars, proc declaration is normally global."
proc inner {} {puts "If you want a local proc, just use a namespace."}}}
% outer
If a proc is declared inside another proc, is it local?
% middle
No. Unlike vars, proc declaration is normally global.
% inner
If you want a local proc, just use a namespace.
%[brian] - 2009-12-15 08:10:53<How do I access the name of the proc from within the proc itself?>Beware: with
proc FooBar {} {puts "my name is [info level 1]"}MGS I believe you want something like: proc foo {args} {
puts "proc = [lindex [info level 0] 0]"
}See: info levelDiscussion edit
- Charles Babbage, 1864
- 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.
See Also edit
- Procs as data structures
- Procs as objects
- Runtime creation of procs
- Simple proc tracing
- mkproc
- If we had no proc
- saving all procedures
- apply
