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

stupid question on try finally

40 views
Skip to first unread message

Harald Oehlmann

unread,
Aug 23, 2021, 10:39:25 AM8/23/21
to
Dear TCL'ers,

each question should be asked one day, sorry.

What is the difference between:

set f [open /some/file/name a]
try {
puts $f "some message"
} finally {
close $f
}

and

set f [open /some/file/name a]
try {
puts $f "some message"
}
close $f

The example is from the try manpage.
Anyway, despite what happens within the try block, execution continuous
after it. So, waht is the difference to a finally block.

Or is it even executed, if we escape from a catch block ?

proc t {} {
set f [open /some/file/name a]
try {
puts $f "some message"
} trap {} {} {
return
} finally {
close $f
}
}

So, on error, there is a return, but the close is executed magically
before the return.

Sorry, I just don't see it.

Thanks,
Harald

Rich

unread,
Aug 23, 2021, 10:54:18 AM8/23/21
to
Harald Oehlmann <wort...@yahoo.de> wrote:
> Dear TCL'ers,
>
> each question should be asked one day, sorry.
>
> What is the difference between:
>
> set f [open /some/file/name a]
> try {
> puts $f "some message"
> } finally {
> close $f
> }
>
> and
>
> set f [open /some/file/name a]
> try {
> puts $f "some message"
> }
> close $f

The above two look to have identical results.

> Or is it even executed, if we escape from a catch block ?
>
> proc t {} {
> set f [open /some/file/name a]
> try {
> puts $f "some message"
> } trap {} {} {
> return
> } finally {
> close $f
> }
> }
>
> So, on error, there is a return, but the close is executed magically
> before the return.

According to the man page:

Note that the finally clause is processed even if an error occurs
and irrespective of which, if any, handler is used.

So think of it as "always finish by running this block". So in your
second example, I expect the finally to execute even though the trap
did a return.

And, if you test it in a REPL, you see that is the case:

$ rlwrap tclsh
% proc t {} {
try {
error "BAM"
} trap {} {} {
puts stderr "running 'trap'"
return
} finally {
puts stderr "running 'finally'"
}
}
% t
running 'trap'
running 'finally'
%

Harald Oehlmann

unread,
Aug 23, 2021, 11:23:51 AM8/23/21
to
Thank you, rich, I appreciate.
So, the big benefit is, that if a handler exits a proc the finally
clause is executed, but the result of return is returned to the caller.
That is weired.

% proc t {} {try {error q} trap {} {} {puts t;return 5} finally {puts
f};puts e}
% puts R=[t]
t
f
R=5

It is incredible, that you can execute something after a return command,
wow !

Thank you,
Harald

Rich

unread,
Aug 23, 2021, 11:33:18 AM8/23/21
to
Well, the man page says the 'finally' block is processed even if an
error happens and no matter which handler is used. But it appears to
make no statement as to what order that happens.

> % proc t {} {try {error q} trap {} {} {puts t;return 5} finally {puts
> f};puts e}
> % puts R=[t]
> t
> f
> R=5
>
> It is incredible, that you can execute something after a return command,
> wow !

It is probably not "after the return" in a strict sense. What likely
happens is that the 'return' signals "end of handler block", at which
point the 'finally' is executed, and then the return process completes.

But yes, it does look a lot like "after the return".

Harald Oehlmann

unread,
Aug 23, 2021, 11:46:06 AM8/23/21
to
Rich,
thank you for the discussion. A part is added on the wiki page:

https://wiki.tcl-lang.org/page/try

Feel free to modify.

A native speaker (e.g. not me) may judge, if the man page is clear
enough. Nevertheless, I would appreciate an example like on the wiki now
and some clarifying words.

Thank you,
Harald

Rich

unread,
Aug 23, 2021, 12:12:40 PM8/23/21
to
Harald Oehlmann <wort...@yahoo.de> wrote:
> Rich,
> thank you for the discussion. A part is added on the wiki page:
>
> https://wiki.tcl-lang.org/page/try
>
> Feel free to modify.
>
> A native speaker (e.g. not me) may judge, if the man page is clear
> enough. Nevertheless, I would appreciate an example like on the wiki now
> and some clarifying words.

You say this in the Wiki:

I only see a use-case for this case. Otherwise, you may just write
the finally part after the try command and all is the same.

I see the 'use case' for finally as being able to place all cleanup
code in one spot.

I.e., no 'try':

proc x {...} {
# do something that allocates something that we have to manually
# deallocate (opening files, creating a struct::matrix or
# struct::graph, etc.)

set r [catch {perform something that might error} a b]

if {$r} {
# caught an error
# we have to cleanup, here, all the stuff we allocated at entry to
# the proc
return -code error
}

# normal no error code path
# ...
# ...
# ...
# ...

# done - now we have to cleanup everything we allocated at the start
# of the proc

return
}

In the above, as the proc evolves, we might allocate more (or less)
stuff at the start of the proc, and we have (above) two places in the
proc to edit for "cleanup". Two separate places to edit, containing
the same code, means they might get out of sync with each other. And,
because they are error handling paths, an out of sync error path will
go unnoticed until the error happens to trigger one day.

With 'finally', the proc can be refactored to be:

proc x {...} {
# allocate stuff

try {
# ...
} trap {} {} {
# ...
} trap {} {} {
# ...
} finally {
# cleanup the allocated stuff
}
}

Now, no matter how many different 'trap' handlers you use, there's only
one cleanup, and it always executes, so cleanup always occurs. Less
code duplication, less chance of code getting out of sync.

Harald Oehlmann

unread,
Aug 23, 2021, 12:19:09 PM8/23/21
to
Dear Rich,

thank you. But your example is exactly the case where I see the value.
The error handler gives the exit value by return. This exit value is
preserved and the cleanup is handled in any case.

But if you omit the "return -code error" in the handler, then the
cleanup may be written below the try block without any difference.

Please modify the wiki, if this is not clear.

It may be noted, that "error 'return from trap'" may be replaced by any
command which terminates the proc and returns a value. Other commands
are "error "xxx"" or "return -code error".

Thank you,
Harald
0 new messages