23 Jun 22:15
Re: Garbage collected handles / on_leave_frame / finally
From: Twylite <twylite@...>
Subject: Re: Garbage collected handles / on_leave_frame / finally
Newsgroups: gmane.comp.lang.tcl.core
Date: 2008-06-23 20:15:32 GMT
Subject: Re: Garbage collected handles / on_leave_frame / finally
Newsgroups: gmane.comp.lang.tcl.core
Date: 2008-06-23 20:15:32 GMT
Hi, I'm only vaguely following this conversation so please disregard if OT. > From: "Alexandre Ferrieux" <alexandre.ferrieux@...> > proc foo {} { > set x [somecreator] > on_leave_frame 0 [list destroy $x] > } > I like it, but for a different reason :) I've been mulling a TIP for a "finally" command that is not part of a try/finally construct. Such a command would allow one or more "finally scripts" to be associated with a scope and evaluated when execution leaves the scope/frame. The benefits are a simplification of error handling and support for freeing resources that are used within the scope. I wasn't going as far as indicating the stack level / frame to which to attach the script though ;) The simplification comes from less noise. Consider simple file-parsing code: Approach #A.1 - Leaks file handles set f [open $myfile r] # ... process data in $f ... don't use return here close $f Approach #A.2 - Tcl catch set f [open $myfile r] set failed [catch { # ... process data in $f ... don't use return here } em opts] close $f ;# finally return -options $options -level 1 $em ;# return or rethrow Approach #A.3 - Try/finally set f [open $myfile r] try { # ... process data in $f ... don't use return here } finally { close $f } This approach may require an additional result capture in the try and return $result at the end, depending on whether the try/finally returns the result of the try block or the finally block (TIP 89 appears to do the former, which is good). Approach #A.4 - scoped finally scripts set f [open $myfile r] finally { close $f } # ... process data in $f ... can use return here Even in a simple case the scoped finally is terse, but it really shines in places where a nested try/finally would be required: Approach #B.1 - nested try/finally proc printrows {id} { global dbhandle set stmt [$dbhandle prepare "SELECT * FROM t_table WHERE id = :myid"] try { set resultset [$stmt execute] try { while { [$resultset nextrow rowdict] } { puts "Got row '$rowdict'" } } finally { $resultset close } } finally { $stmt close } } Approach #B.2 - scoped finally scripts proc printrows {id} { global dbhandle set stmt [$dbhandle prepare "SELECT * FROM t_table WHERE id = :myid"] finally { $stmt close } set resultset [$stmt execute] finally { $stmt close } while { [$resultset nextrow rowdict] } { puts "Got row '$rowdict'" } } A scoped finally script can also make finally clauses safer. There are occasions where a finally clause must take multiple actions (say close a statement and write a log entry). In such cases an exception in the finally handler may cause resources to leak. In my experience errors in catch/finally handlers are quite common as they are not as well tested as code on the "expected path". Using separate finally scripts may provide more reliable error handling. Any thoughts? (FWIW I say "mulling a TIP" because I'm not very familiar with Tcl internals and I don't really know how to implement this). > From: Neil Madden <nem@...> > You could do, but my proposal doesn't tie lifecycles to stack-frames. It > ties life cycles to ref-counts and ref-counts are added/removed by > command names (in scopes). Tying lifecycles in the way you described > *is* equivalent to try/finally, as the object cannot escape the scope it > is tied to -- so you end up with everything back at the global scope. > If I'm following this, the problem is tracking the references to a resource, and sometimes those references (strings) may be part of a callback script (to fileevent, after, etc) that will be eval'ed later. So basically the reference (string) may be included in some string or list, and the original Tcl_Obj will reach refcount zero when execution leaves the scope and the resource is prematurely freed? I've heard discussion of lambdas that could capture the local scope - wouldn't that be a potential approach? Regards, Trevor ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php
RSS Feed