Twylite | 23 Jun 22:15
Picon

Re: Garbage collected handles / on_leave_frame / finally

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

Gmane