Reputation: 27
I must use a proc Z, which returns something like "return -code 2" $something , but I can't understand how it's works.
proc X {} {
puts "X - in"
Y
puts "X - out"
}
proc Y {} {
puts "Y - in"
Z
puts "Y - out"
}
proc Z {} {
puts "Z - in"
return -code 2 "some value"
puts "Z - out"
}
X
Output is :
X - in
Y - in
Z - in
X - out
I can't change return in proc Z, but I also want that it continues his work in proc Y and puts "Y-out". Can i do it ?
Upvotes: 0
Views: 221
Reputation: 137587
The return
command conceptually raises an exception (of type return
, which corresponds to the TCL_RETURN
result code in the Tcl C API) that is trapped by the procedure (strictly, by the procedure hull that does things like callframe management and argument marshalling) in which it runs to make that do something. In the case of a normal return
, it simply makes the procedure return that value, but when the -code
option is provided, it can direct the procedure to do something else; this is done after the callframe has been popped from the Tcl call stack.
Because 2
is the actual value of the TCL_RETURN
result code, it means that it is telling the procedure hull (i.e., the overall Z
procedure) to behave like it was a simple call to return
, which is why puts "Y - out"
isn't being executed; there's a return exception being processed as a result of the execution of Z
. (FWIW, return -code 2
is pretty rare. return -code 1
/return -code error
is much more common, as it is a way of getting an error exception to be thrown, which is useful because stack traces are only built by error exceptions.)
You can override this processing using catch
or try
. It's a bit easier to get this right with try
, since catch
is a fairly broad-brush primitive. Try this:
proc Y {} {
puts "Y - in"
try {
Z
} on return {msg} {
puts "Z told us to return '$msg'"
}
puts "Y - out"
}
If you're just wanting to make a short piece of code work after the call but otherwise not interfere, try
…finally
is the right way:
proc Y {} {
puts "Y - in"
try {
Z
} finally {
puts "Y - out"
}
}
If you're using Tcl 8.5 (or before), you won't have try
. Here's a version with catch
:
proc Y {} {
puts "Y - in"
set code [catch {
Z
} msg]
if {$code == 2} {
puts "Z told us to return '$msg'"
}
puts "Y - out"
}
The problem with catch
is that it is very easy to lose errors by accident.
Upvotes: 2