Sujet : Re: try... query
De : nospam.nurdglaw (at) *nospam* gmail.com (Alan Grunwald)
Groupes : comp.lang.tclDate : 06. Dec 2024, 21:00:51
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <vivl7c$2hmkl$1@dont-email.me>
References : 1 2
User-Agent : Mozilla Thunderbird
On 06/12/2024 13:42, Harald Oehlmann wrote:
Am 06.12.2024 um 14:11 schrieb Alan Grunwald:
I'm attempting to get my head around preventing resource leaks, using try and return. In fact I thought I had understood the mechanisms well enough to use them and had come up with a structure like this:
>
proc allocateResources {} {
set obj1 [Some_mechanism]
try {
set obj2 [Some_other_mechanism]
try {
do_various_other_stuff
} on error {message errorDict} {
$obj2 destroy
return \
-code error \
-errorcode [dict get $errorDict -errorcode] \
-errorinfo [dict get $errorDict -errorinfo] \
$message
}
} on error {
$obj1 destroy
return \
-code error \
-errorcode [dict get $errorDict -errorcode] \
-errorinfo [dict get $errorDict -errorinfo] \
$message
}
>
return [list $obj1 $obj2]
}
>
If all is well, I expect the caller of allocateResources to destroy the objects when it has finished with them.
>
There are a couple of areas of this code that I don't completely (?!) understand:
>
1) I was assuming that if there was an error in do_various_other_stuff if would be caught by the inner 'on error' clause, which would delete obj2 and raise another error that would be caught by the outer 'on error' clause, which would delete obj1. Experiment suggests that this doesn't happen and the outer 'on error' clause isn't executed.
>
2) Originally, I wasn't including -errorinfo in the return statements in the 'on error' clauses, but I found that the stack trace didn't properly identify the line causing the error. Including -errorinfo seems to have cured that problem.
>
So,
>
Q1) Have I misunderstood the way try... works, or is my problem elsewhere? I realise that I could do away with the nested try... statement and check whether obj1 and obj2 exist and only destroy them if they do, but that seems clunky.
>
Q2) Have I coded the return statements properly to get the error information to propagate correctly? I have a vague memory of doing it this way sometime in the past only for some other issue to emerge that I corrected by not using -errorinfo.
>
Thanks,
>
Alan
>
PS For what it's worth, I am using a home-built tcl9.0.0 on Linux Mint.
Alan,
great post.
Thank you.
. An eventual finally clause is executed in any case, even on
error and on a return within the try case.
For example for a file to be closed on success or error:
proc readfile filename {
# if open fails, there is no resource to close, so keep out of try
set f [open $filename r]
# Now, the file must be closed in any case, so start try
try {
fconfigure $f -encoding utf-8
return [read $f]
} finally {
# close in success case, or in read or fconfigure error case
close $f
}
}
You can also nest:
proc readfile filename {
# if open fails, there is no resource to close, so keep out of try
set f [open $filename r]
# Now, the file must be closed in any case, so start try
try {
fconfigure $f -encoding utf-8
set data [read $f]
# parse data by tdom, which opens another resource
tdom::parse $data handle
try {
return [$handle match abc]
} finally {
$handle destroy
}
} finally {
# close in success case, or in read or fconfigure error case
close $f
}
}
Errr. No.
I had carefully crafted my example to demonstrate that deleting objects in a finally clause would not be appropriate, since if there is no error the "normal" return statement will return the two objects and the caller of allocateResources will be responsible for deleting them.
Thank you very much for your examples of different use cases. Is it possible to achieve what I would like? Is it possible with something other than using a single try statement that has an on error clause like
if {[info exists obj1] && $obj1 in [info commands $obj1]} {
$obj1 destroy
}
if {[info exists obj2] && $obj2 in [info commands $obj2]} {
$obj2 destroy
}
or does this represent minimal clunkiness?