While tooling around with Lua recently I realised that it would be useful to have an equivalent of the Common Lisp macro with-open-file. It's not something you need in Perl, where the reference counting ensures that a file handle is closed as soon as the local variable it's stored in goes out of scope, but Lua uses garbage collection, so a file handle you're finished with will hang around until the garbage collector notices that it's no longer referenced from anywhere. If your program opens lots of files in quick succession it's important to close them as soon as possible to avoid running out of file descriptors.
In Lisp you can use the with-open-file macro to automatically
insert the code to close the file after the chunk of code that uses it,
like this:
(with-open-file (f "output.txt" :direction :output) (format f "Here are a couple~%of test data lines~%"))
Lua doesn't have macros, but in this case we can do the same sort of thing by providing a block of code in an anonymous function:
with_open_file("output.txt", "wb", function (f) f:write("some numbers:\n") for i = 1, 10 do f:write(i, "\n") end end)
All the with_open_file function has to do is handle the
opening and closing of the file for us, and pass it in to the function
where it's used. Here's my implementation:
function with_open_file (filename, mode, code) local file = assert(io.open(filename, mode)) local ok, result = pcall(code, file) file:close() assert(ok, result) return result end
I'm using pcall to call the anonymous function in ‘protected
mode’ (Lua's equivalent of a try block) so that I can close the
file even if an exception is thrown. The original exception gets rethrown by
assert. I'm also allowing the inner function to return a result
through with_open_file, although I don't think I've needed that
yet.