What's "with" edit
It's a construct that can automatically clean up "garbage" after finishing a task.
For example,
open is usually combined with a
chan close. A "with" construct will automatically close the file descriptor (aka. handle). See also
withOpenFile.
Reasonably use the "with" construct can make your code visibly clearer.
One possible implementation edit
proc getFinalByOp {op opret} {
switch -exact -- $op {
open {
return [list chan close $opret]
}
default {
return [list]
}
}
}
#
# op: a command
# opargs: @op's arguments
# body: code that will be executed
# ?_finally?: provide a 'finally' yourself
# ?varname?: result of @op
#
proc with {op opargs body {_finally {}} {varname handle} } {
set finally $_finally
try {
set [set varname] [$op {*}$opargs]
if {$finally eq {}} {
set finally [getFinalByOp $op [set [set varname]]]
}
eval $body
} finally {
eval $finally
}
}
This implementation only supports
open, it's not extensive, and it's buggy (see Discussions below).
How to use it edit
with open {a.txt w} {chan puts $handle "hello world"}
with open {a.txt r} {puts [read $fd]} {} fd
with puts {"a test"} {set a {hello}} {puts $a} ;# a meaningless example
A more complex example edit
Read in a file (employees.txt) of the following format,
name1,salary1
name2,salary2
name3,salary3
The real file is,
Mike Foo,10000
Jack Bar,2000
John Doe,3000
If salary < 3000, add 200, and in the end print the result, write it back.
A possible implementation (can be easier?),
# ... "with" here ...
with open {employees.txt r+} {
set contents [chan read -nonewline $handle]
foreach line [split $contents \n] {
set list [split $line ,]
if {[lindex $list 1] < 3000} {
lset list 1 [expr {200+[lindex $list 1]}]
}
lappend result "[lindex $list 0],[lindex $list 1]"
}
chan seek $handle 0
chan truncate $handle 0
puts [join $result \n]
chan puts -nonewline $handle [join $result \n]
}
Discussions edit
From the IRC channel,
<miguel> I am afraid that 'general with' will not work - not with bodies that try to use variables from the calling env
<miguel> ... nor with commands that resolv differently in the calling env and in the proc's namespace
cyril: I have a much simpler implementation
https://github.com/cyrilthomas/with