Concise multiple do-block


#1

Hello,

Is there a concise way of opening multiple files simultaneously in a do-block construct? This only to save indents, really.

open("one") do fd1
   open("two") do fd2
       open("out", "w") do out
           ## lots of indent for using fd1, fd, out
       end
   end
end

Thanks,
—david


#2

I’ve recently been running into the same thing. Probably not the best, but the solution I’ve been using is:

open("one") do fd1; open("two") do fd2;  open("out", "w") do out
     # do stuff with one indent because whitespace doesn't actually matter!
end; end; end

Not the prettiest solution, but it works! (note: you don’t actually even need the semicolons, but it makes things a bit clearer to me)


#3

Lisp-y recursion comes in pretty handy in this case:


Main> openall(f::Function, file::AbstractString, other_files...) =
           openall(f, (file, "r"), other_files...)
openall (generic function with 1 method)

Main> function openall(f::Function, file::Tuple, other_files...)
           open(file...) do handle
               openall(other_files...) do handles...
                   f(handle, handles...)
               end
           end
       end
openall (generic function with 2 methods)

Main> openall(f::Function) = f()
openall (generic function with 3 methods)

Main> openall("f1") do f1
           @show f1
       end
f1 = IOStream(<file f1>)
IOStream(<file f1>)

Main> openall("f1", ("f2", "w")) do f1, f2
           @show f1 f2
       end
f1 = IOStream(<file f1>)
f2 = IOStream(<file f2>)
IOStream(<file f2>)

Main> openall("f1", ("f2", "a"), "f3", ("f4", "w")) do f1, f2, f3, f4
           @show f1 f2 f3 f4
       end
f1 = IOStream(<file f1>)
f2 = IOStream(<file f2>)
f3 = IOStream(<file f3>)
f4 = IOStream(<file f4>)
IOStream(<file f4>)

#4

This proposed feature would help quite a bit:

https://github.com/JuliaLang/julia/issues/7721#issuecomment-171345256

You could write this particular example as:

fd1 = open("one")!
fd2 = open("two")!
out = open("out", "w")!
## no indent for using fd1, fd, out
# all handles closed when scope ends

#5

Nice. What I like about the f(x)! syntax is that code that works with the exclamation mark at the end of the function will (most of the time?) work without it as well, making this syntax flexible and forgiving and therefore easier to adopt.


#6

Ah, yes, I remember this discussion from a while ago now. Has anyone picked up implementing the ()! construct?

In another thread I am busy with trying to figure out how to make a python-style generator that produces IO objects. The idea would be that the generator creates and opens the IO, and the caller/consumer uses the object until the next item. Then when the caller is done with the object, the GC should come in and trigger a close() on the IO object. (If this would be the mechanism, the GC should probably also be triggered by a low-on-filedescriptors event).