D programming language has an interesting construct, scope(exit), that arranges something to be done when leaving the enclosing block. ====== { auto fd = File("/dev/null"); scope(exit) { close(fd); } ... } ====== The same thing is added easily to TCL: ====== proc scope(exit) {args} { upvar {___ scope guard} guard set guard "" trace add variable guard unset \ [list %scope(exit)onTrace [uplevel 1 {namespace current}] $args] } proc %scope(exit)onTrace {nativeNamespace command name1 name2 op} { namespace eval $nativeNamespace $command } proc test {} { set channel [open [info nameofexecutable] r] scope(exit) close $channel scope(exit) puts "Bye-bye. Channel closed: $channel" } ====== It can be argued that try ... finally or catch ... return may do the same, but the advantage of scope(exit) is that a clean-up command for each resource may be declared near the place where the resource is allocated. Thus using scope(exit) may improve code readability. Two or three bad things about this hack: * When the cleanup command is called, the stack frame of the enclosing procedure is already deleted. Things as scope(exit) { close $fd } are impossible: $fd substitution can not happen in scope exit handler * Errors from the scope exit handlers are silently ignored. * In TCL, a loop/if/eval/catch/etc. body does not have its own scope. Because of this, scope(exit) semantics may be unobvious here: ====== while {$something} { open something... scope(exit) cleanup something ;# doesn't work as expected } ====== ------ [NEM] A similar approach is taken in the [generator] package I wrote recently [http://www.cs.nott.ac.uk/~nem/tcl/generator.html]. In that package, there is a ''generator finally'' command that can be used to register cleanup to be performed when the generator is destroyed, which is a form of scope-based cleanup. This simplified the cleanup code, as then you don't need any complex signalling or exception handling mechanism to ensure that resources are cleaned up even in the case of early termination of a generator. For example: ====== generator define lines file { set in [open $file] generator finally close $in ;# ensure cleanup on exit while {[gets $in line]} { generator yield $line } } generator foreach line [lines /etc/passwd] { puts [format "%4d| %s" [incr lineNum] $line] } ====== ---- [A/AK] I also began to value this hack with the appearing of coroutines. It's interesting (and sad) that it's now ''the only way'' to clean up something when coroutine is deleted. try { yield } finally { cleanup } doesn't provide it. And it's not something that can be fixed easily. If there would be some [catch]able unwinding when coroutine is deleted, it would lead to as many potential bugs as it would fix. Making [try] .. finally do something different than [catch] could be a better way, but it would break current semantics of [catch] as an universal exception-handling primitive.