Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

try {} and return

73 views
Skip to first unread message

Roger Oberholtzer

unread,
Jun 30, 2016, 4:16:52 AM6/30/16
to
If one does the following:

proc x {} {

set f [open "zz" rb]
try {

return [binary encode base64 [read $f]]

} finally {

close $f
}
}

The initial clause completes without an error, so the return must have happened. Will the finally {} still be able to execute the close in the context of the proc? 'f' is a local variable.

I think it does in fact close f. But it seems odd to be able to access a variable local to x after a return from x.

Rich

unread,
Jun 30, 2016, 6:22:46 AM6/30/16
to
A simplified variant, in order to test what actually occurs:

proc x {} {

try {
puts stderr "About to \[return\] from x"
return 42
} finally {
puts stderr "Inside finally clause"
}
}

puts stderr "Calling x"
x
puts stderr "Back from x"

Now, running the above:

$ tclsh test
Calling x
About to [return] from x
Inside finally clause
Back from x
$

So, the answer is, yes.

Note as well the documentation of try:

SYNOPSIS
try body ?handler...? ?finally script?

DESCRIPTION
This command executes the script body and, depending on what the
outcome of that script is (normal exit, error, or some other
exceptional result), runs a handler script to deal with the case.
Once that has all happened, if the finally clause is present, the
script it includes will be run and the result of the handler (or
the body if no handler matched) is allowed to continue to
propagate. Note that the finally clause is processed even if an
error occurs and irrespective of which, if any, handler is used.

The important part is _executes the script body and, depending on what
the outcome of that script is (normal exit, error, or some other
exceptional result), runs a handler script to deal with the case._

So when inside the try, the [return] is not returning from x, it is
returning from the "body" script that was passed to try.

Donal K. Fellows

unread,
Jun 30, 2016, 6:33:38 AM6/30/16
to
On 30/06/2016 09:16, Roger Oberholtzer wrote:
> Will the finally {} still be able to execute the close in the context of the proc?

Yes. It traps the [return]'s special exception, runs the finally block,
and then re-throws the [return] which makes the procedure actually
return. It'd be nothing like so useful if this didn't Just Work. :-) If
you want to explore what's going on in detail, try this:

set returnCode [catch {
return "a dummy value"
} message statusDictionary]
puts "return code was $returnCode"
puts "result was '$message'"
puts "status dictionary:"
dict for {k v} $statusDictionary {puts "\t${k}: ${v}"}

Run that and you'll get this output:

return code was 2
result was 'a dummy value'
status dictionary:
-code: 0
-level: 1

The '2' is the result code TCL_RETURN. The '0' is TCL_OK, the result
code to use from the procedure. The -level is how many levels of stack
frame (or is that levels of procedure?) to unwind; '1' is normal for a
basic [return].

One of the points of putting [try] into Tcl was to make exactly this
sort of thing much easier. It does nothing you couldn't do with [catch]
and some scripting, but doing that is really annoying: [try] hides the
mess and lets you write clearer code. In fact, the only thing you need
to watch out for is whether your 'finally' clause throws an error: if it
does, it can make it harder to work out what the main body was up to.

The variable lifespan is to the end of the procedure (or an explicit
[unset]), not to the point where [return] was called. That was always
the case.

Donal.
--
Donal Fellows — Tcl user, Tcl maintainer, TIP editor.

Roger Oberholtzer

unread,
Jun 30, 2016, 6:36:14 AM6/30/16
to
On Thursday, June 30, 2016 at 12:22:46 PM UTC+2, Rich wrote:

> The important part is _executes the script body and, depending on what
> the outcome of that script is (normal exit, error, or some other
> exceptional result), runs a handler script to deal with the case._
>
> So when inside the try, the [return] is not returning from x, it is
> returning from the "body" script that was passed to try.

Ok. The return from the clause makes sense. And the proc returns what the successful first clause returned.

I wonder if there would be any copy by Tcl of the data returned from the first clause when later returning that as the result from the proc. This is in relation to the post in this list with Subject: "Performance Issue: Foreach loops, Catch and Large Data Structures".

EL

unread,
Jun 30, 2016, 1:22:04 PM6/30/16
to
Am 30.06.16 um 10:16 schrieb Roger Oberholtzer:

> But it seems odd to be able to access a variable local to x after a return from x.

That is the exact purpose of a finally clause. It is *always* executed,
especially regardless of whether there was an error or not.
Also the commands are substituted inside out. So, in the case of

return [binary encode base64 [read $f]]

the [read $f] is executed first, then the [binary encode] with the
output from [read $f], then [return]. At the time the [return] is
executed, the file handle reading is already finished and the close can
safely happen.


--
EL
0 new messages