lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



On 12-Aug-05, at 8:08 AM, Roberto Ierusalimschy wrote:

I still think that we can do that with finalizers. As long as each
object has a proper finalizer (i.e., a __gc metamethod), all we have to
do in case of errors is to call collectgarbage() to finalize what was
left.

There are lots of things that can be done with gc finalizers, but I think they fall into a different category than the things that maybe should be done with cleanup clauses.

A gc finalizer is good for deallocation of resources, but it doesn't solve the problem of maintaining state which is aligned with the dynamic execution state.

To be slightly less theoretical :), Lua's io library still contains the io.input and io.output methods, which could be quite handy for temporarily diverting input and output:

function with_output(f, func, ...)
  local out = io.output()
  io.output(f)
  func(...)
  io.output(out)
end


This suffers from two problems: first, it will fail if func throws an error, and second, I'm tossing away func's return value(s).

I can fix the first problem by pcall'ing func, but I might be reluctant to do that for a couple of reasons: (1) pcall'ing defeats yield(), (2) I would then end up having captured an error I'm not interested in.

Similarly, I can fix the second problem by keeping some number of return values (probably 1) or using some complicated mechanism for keeping a vector of return values and then saving them.

So I might end up with something like this (which also has some flaws):

function capture(flag, ...)
  -- unpredictable results if ... contains a nil
  if flag then return flag, {...}
          else return flag, (...)
  end
end


function with_output(f, ...)
  local out = io.output()
  io.output(f)
  local flag, rv = capture(pcall(...))
  io.output(out)
  if flag then return unpack(rv)
          else error(rv, 0)
  end
end


Contrast with:

function with_output(f, func, ...)
  local out = io.output()
  return block (ret)
    ret(func(...))
  finally
    io.output(out)
  end
end

Provided the compiler were clever enough to not use TAILCALL inside a block, this could be written:

function with_output(f, func, ...)
  local out = io.output()
  block()
    return func(...)
  finally
    io.output(out)
  end
end