return, a
built-in Tcl command, returns a value, a code and other options from a particular
level.
Synopsis edit
-
- return ?result
-
- return ?-code code? ?result
-
- return ?option value? ?result
- -errorcode list
- -errorinfo info
- -errorstack list
- added in Tcl8.6
- -level level
- -options options
Documentation edit
- official reference
- TIP 90, Enable return -code in Control Structure Procs
Description edit
Delivers a return code for some level to the interpreter, which then takes some action based on the received code. By far the most common use case is to return a value from the current procedure:
proc knightswhosay {} {
return Ni!
}
-level is a positive integer indicating the number of levels up from the current level. Level
0 is the evaluation of
return itself, level
1 is the caller of return, and so on.
-code is a positive integer or the symbolic value as specified later on this page. By default, the value of
-code is
1 (
ok) and the value of
-level is
1. The following three commands all effectively instruct the caller to
return normally from the current procedure (level 1):
return
return -level 0 -code return
return -level 1 -code ok
The return value is either the final argument or the
empty string.
catch and
try can be used to intercept a return.
Any additional
option/
value pairs are added to the options dictionary for the level.
[TODO: Document Tcl 8.5's extended handling] Return Codes edit
Typically,
-code isn't specified and the level returns a normally, i.e. with a completion code of
TCL_OK. However,
-code may be any of the following numeric or alphabetic values,
- 0
- ok
- Success. return -level 1 -code ok is the same as return. (TCL_OK)
- 1
- error
- An error. return -level 0 -code error is the same as error. (TCL_ERROR)
- 2
- return
- Cause the level up to return. return -level 0 -code return has the same effect as return, as well as return -level 1 -code ok. (TCL_RETURN).
- 3
- break
- Instruct the next level up break out of the innermost nested loop in the current script. return -level 0 -code break is the same as break. (TCL_BREAK)
- 4
- continue
- Instruct the next level up to terminate the current iteration of the innermost nested loop in the code that invoked the current procedure and start the next iteration. (TCL_CONTINUE)
- value
- Any integer. User-defined behaviour. Rarely used with values outside the range 0..4.
-code is rarely used, as commands such as
error,
break and
continue handle the common cases. The less common case is that a procedure implements a
new control structure and needs act, within its caller, like
break,
continue, or
error. In other words, it needs
return -level 1 ... instead of
return -level 0 .... Another use case for
-code is to have the caller, rather than the current procedure, report that the wrong number of arguments were provided, since this makes the error message more clear. Again, what's needed is
return -level 1 -code error instead of
return -level 0 -code error.
Two additional options,
-errorinfo and
-errorcode, may be used to provide additional information during error returns. These options are ignored unless
-code is
error.
-errorinfo specifies an initial stack trace for
$errorInfo. If it is not specified, the stack trace left in
$errorInfo will include the call to the procedure and higher levels on the stack but it will not include any information about the context of the error within the procedure. Typically the
info value is supplied from the value left in
$errorInfo when
catch traps an error within the procedure.
If
-errorcode is specified,
list provides a value for
$errorCode. Otherwise,
$errorCode will default to
NONE. (from:
Tcl Help)
Hack: Arbitrary Data after return edit
After
return, your script can contain whatever, for instance comments:
proc foo {} {
puts Foo
return
This is not Tcl - code after the return is never evaluated so
may be used for commenting...
} ;# RS
DGP: In Tcl 7 and in recent enough Tcl 8.5 that is correct. In the releases in between, due to some limitations in the
bytecode compiler/execution machinery it could not be "whatever":
- braces still needed to be balanced
- Commands like set get byte-compiled early, so a syntax error is found if a line in that post-return comment starts with set and has more than two other words.
Joe English also disagrees that "whatever" can appear after
return.
proc interprets its third argument as a script. It's therefore unwise, and one could argue even illegal, to pass in something that's not at least syntactically valid as a script, even if you know that parts of it will never be executed. By way of analogy:
lindex interprets its first argument as a list, so you'd better only pass it valid lists. In Tcl 7.6 and earlier you could actually get away with things like
lindex "a b c {bad{list" 1
as long as the
examined part of the list was syntactically valid. However, this was more of an accidental artifact of implementation details than anything guaranteed by the language, and in fact this raises an error in more recent Tcl versions. Similarly, if a command expects a script, you'd better pass it a script.
PYK 2013-12-10: However, if
lindex is missing its second value, the first value can still be any value, even one that isn't a valid
list.
AMG: There's a reason for this. When [lindex] is given only one argument, it interprets that as instruction to not perform any list indexing. No list indexing means no requirement to be a list. It's that simple.
jenglish's statement is correct, though it's more philosophical than practical. If [return] is redefined, code following the [return] could certainly come into play. Or perhaps the code isn't being executed but rather is being analyzed by
Nagelfar, which will surely take issue with the invalidity of the code. One real possibility which would upset Tcl in any event is if the text following [return] contains mismatched braces.
And last, I really ought to mention that the first time Tcl runs the proc, it tries to
bytecode the whole thing, which means wasting time analyzing garbage. If there's any doubt about the finality of the [return] (e.g. a conditional is in play), the compiled proc will contain code to return any errors found in parsing.
proc moo {x} {
if {$x} {return 5}
"invalid"asdf
}
% tcl::unsupported::disassemble proc moo
ByteCode 0x0x913eb0, refCt 1, epoch 15, interp 0x0x8c6ac0 (epoch 15)
Source "\nif {$x} {return 5}\n\"invalid\"a"...
Cmds 2, src 34, inst 26, litObjs 4, aux 0, stkDepth 2, code/src 0.00
Proc 0x0x95b5e0, refCt 1, args 1, compiled locals 1
slot 0, scalar, arg, "x"
Commands 2:
1: pc 0-11, src 1-18 2: pc 4-6, src 10-17
Command 1: "if {$x} {return 5}"...
(0) loadScalar1 %v0 # var "x"
(2) jumpFalse1 +7 # pc 9
Command 2: "return 5"...
(4) push1 0 # "5"
(6) done
(7) nop
(8) nop
(9) push1 1 # ""
(11) pop
(12) push1 2 # "extra characters after close-quote"
(14) push1 3 # "-code 1 -level 0 -errorcode NONE -errori"...
(16) syntax +1 0
(25) done
The fact that
return also terminates
source can be used for loading
array contents without specifying an array name. Let the file t.tcl contain:
return {
one 1
two 2
three 3
}
Then you can write it like this:
array set myArrayName [source t.tcl] ;# RS
wdb: This works, but being a purist, I prefer this text in the file to
source:
list one 1 two 2 three 3
RS 2006-06-23: sure. Just if you have hundreds and thousands of array elements, with
list you'd have to backslash-escape the newlines, while with bracing they need not.
DKF: I'm of the kind of purist which doesn't insist on using
list to indicate listishness; that's an illusion and the
list-compiler knows it.
See
package index script interface guidelines for another use of
return in
source'd scripts: The main use for
return outside procedures is in
pkgIndex.tcl:
if {![package vsatisfies [package provide Tcl] 8.4]} return
which avoids presenting the package to
interps that cannot use it.
return -code error edit
RS 2005-08-08: Using
return -code error in place of plain
error, you get a leaner error traceback which is possibly better to read:
% proc 1 x {if {$x<=0} {error "too small"}}
% proc 2 x {if {$x<=0} {return -code error "too small"}}
% 1 0
too small
% set errorInfo
too small
while executing
"error "too small""
(procedure "1" line 1)
invoked from within
"1 0"
% 2 0
too small
% set errorInfo
too small
while executing
"2 0"
DKF: I find this is useful when distinguishing between problems with the values passed in by the caller (such as if the code really wants a string of length 37, has documented this, and yet the user has given a string of length 28), and problems internal to the code that it isn't reasonable for the caller to try to get right.
return to the Current Level edit
AMG PYK:
return -level 0 $x simply sets the interpreter result to
$x. This is the canonical
identity function; see the linked page for more information.
Cancel an Error edit
HaO: When a return code should be forwarded to the caller, one could remove the
level 0 to not directly trigger an eventual exception here:
if {[catch {script goes here} err options]} {
dict unset options -level
return -options $options
}
This was useful to me in the context of
Tk bind scripts, which return
break if no further bind scripts should process.
return vs falling off the end of the proc edit
PYK 2016-09-15: Historically,
return at the end of a procedure was slightly more performant than a final command that didn't explicitly
return. This isn't the case in modern versions of Tcl, which employ
byte compilation.
Related Commands edit
- source
- eval
- proc
- uplevel
- includes a TclChat discussion on the future of return
- break
- continue
- error
- throw
- yield
- yieldm
- yieldTo
tailcall is also related to
return in that it terminates execution of the current
proc. However, unlike
return,
tailcall's
continuation is not the caller.
yieldTo is also related to
tailcall in that it has a custom continuation.
See Also edit
- Errors management
- namespace eval
- Funky Tcl extensibility
- tricks to play with return -code return and error on return -code error
- try ... finally ...
- KBK 2001-01-02: how to use return -code to implement a new control structure. Lars H: Other pages which do that kind of thing are breakeval (using -code 10) and returneval (using -code -1).
- syntax