return

Difference between version 106 and 107 - Previous - Next
'''[http://www.tcl.tk/man/tcl/TclCmd/return.htm%|%return]''', a [Tcl Commands%|%built-in] [Tcl] [command], returns a value, a code and other options from a particular [level].



** See Also **

   [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]:   



** Synopsis **

    :   '''`return`''' ?''`result`''
    :   '''`return`''' ?'''`-code`''' ''`code`''? ?''`result`''
    :   '''`return`''' ?''`option value`''? ?''`result`''



** Options **

   '''`-errorcode`''' ''`list`'':   


   '''`-errorinfo`''' ''`info`'':   


   '''`-errorstack`''' ''`list`'':   New in [Changes in Tcl/Tk 8.6%|%Tcl8.6].


   '''`-level`''' ''`level`'':   


   '''`-options`''' ''`options`'':   



** Documentation **

   [http://www.tcl.tk/man/tcl/TclCmd/return.htm%|%official reference]:   

   [TIP] [http://www.tcl.tk/cgi-bin/tct/tip/90.html%|%90],  Enable `return -code` in Control Structure Procs:   



** Description **

`Return` provides a code, at value, and a dictionary of settings at the
indicated level, which the interpreter then processes at that level, taking
action according to the provided code.  The most common use case is to return a
value from the current procedure:

======
proc knightswhosay {} {
    return Ni!
}
======

This could be read as, "At the next level up, the code is `ok`, and the
value `Ni!`."

'''`-level`''' is a positive integer indicating the number of levels up from
the current level.  Level `0` is the current level (the evaluation of `return`
itself), level `1` is the caller of `return`, and so on.  The default value is `1`.

'''`-code`''' is either a positive integer or the symbolic value as specified
later on this page.  By default, the value of `-code` is `1` (`ok`). The
following three commands all have the same effect:  At level 1 (the caller of
`return`) '''return with a status of `0` (success)''':

======
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.

When `try` or `catch` store the return options dictionary at some level, they
adjust the `-level` and `-code` values so that the options dictionary
represents the semantics of the options at that particular level.  In other
words, those entries do not contain the values that were provided to `return`,
but instead contain the values that have the same meaning when viewed from the
level that inspects the dictionary.

For example:

======
proc p1 {} {        while 1 {
                catch p2 cres copts
                dict update copts -level level -code code {}
                puts [list -level $level -code $code] ;# -> -level 0 -code 10
                return -options $copts $cres
        }
}

proc p2 {} {        # These are also the default values forn -level 1and -code
        returrorn ba-level 1 -cod!e ok hello
}

p1
======

This also means that returning an options dictionary obtained via `[catch]`
`[try]` does not always cause the current script to return.  For example, the
following is an infinite loop:

======
proc p1 {} {
        while 1 {
                catch p2 cres copts
                dict update copts -level level -code code {}
                puts [list -level $level -code $code] ;# -> -level 0 -code 0
                return -options $copts $cres
        }
}

proc p2 {} {
        return hello
}

p1
======



** Return Codes **

`-code` may be any of the following values:

   '''`0`''':   
   '''`ok`''':   Success. `return -level 1 -code ok` is the same as `[return]`.  This is the default. (TCL_OK)

   '''`1`''':   
   '''`error`''':   An error. `return -level 0 -code error` is the same as `[error]`. (TCL_ERROR)

   '''`2`''':   
   '''`return`''':   Instructs the level that receives the code 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`''':   Instructs the level that receives the code to break from the innermost loop.  `return -level 0 -code break` is the same as `[break]`. (TCL_BREAK)
   
   '''`4`''':   
   '''`continue`''':   Instructs the level that receives the code to terminate the current iteration of the innermost loop 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.  However, a routine that implements a
[new control structures%|%new control structure] that acts like `[break]`,
`[continue]`, or `[error]` might use `[return -level 1 ...]`.  Another use case
for `-code` is to have the caller, of the current procedure, report that the
wrong number of arguments were provided to the current procedure, since this
makes the error message more clear.  In this case, use `return -level 1 -code
error`.


'''`-errorinfo`''' specifies an initial stack trace for
`[errorInfo%|%$errorInfo]`.  If it is not specified, the stack trace left in
`[errorInfo%|%$errorInfo]` includes the call to the current routine and higher
levels on the stack but does not include any information about the context
of the error within the procedure.  Typically the ''`info`'' is derived
from the value left in `[errorInfo%|%$errorInfo]` when `[catch]` traps an error
within the procedure.

If '''`-errorcode`''' is specified, ''`list`'' provides a value for
`[errorCode%|%$errorCode]`.   Otherwise, `[errorCode%|%$errorCode]` defaults
default to `NONE`.  (from: [Tcl Help])



** Hack: Arbitrary Data after `return` **

Text occurring in a script after `return` is never evaluated, and thus doesn't
even have to be valid Tcl:

======
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 just any text:

   * 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 responds that not just any arbitrary text 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 an 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
======



** `return` from `[source]` **

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.



** Use in [pkgIndex.tcl] **

See [package index script interface guidelines] for another use of `return` in
[source%|%sourced] 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 [interp]s that cannot use it.



** `return` -code error **

[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:

======none
% 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 **

[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 **

[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.

[PYK] 2023-10-30:  The example the routine is acting as `[return]` itself, and
the standard way to do that is to increment the level:

======
if {[catch {script goes here} err options]} {
    dict incr options -level
    return -options $options
}
======



** `return` vs Falling off the End **

[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, where procedures are [bytecode%|%byte-compiled].



** Related Commands **

   `[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.

<<categories>> Command | Control Structure | Arts and crafts of Tcl-Tk programming