lua-users home
lua-l archive

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


So, that post about redefining "require" got me thinking about
function wrapping.  It would be neat to have a function "wrap"
such that you could write the "require" redefinition as:

  require = wrap(require, function (f)
    local wasInsideRequire = isInsideRequire
    isInsideRequire = true
    f()
    isInsideRequire = wasInsideRequire
  end)

In general, you pass "wrap" a "wrappee" and a "wrapper":

  wrappedFoo = wrap(foo, function (f)
    stuffToDoBeforeFoo()
    f()   -- foo gets called here, somehow
    stuffToDoAfterFoo()
  end)

The tricky part is that all of the arguments passed to "wrappedFoo"
have to be shuttled into "foo", and all the results of "foo" have
to be shuttled out of "wrappedFoo"!

Here's the straightforward implementation:

  function wrap (wrappee,wrapper)
     return function (...)
        local args = { ... }
        local results
        wrapper( function ()
            results = { wrappee(unpack(args)) }
        end)
        return unpack(results)
     end
  end
  
That works, but there's sure a lot of unpacking going on.  I wondered
if it could be implemented without tables, keeping everything on the
stack.  After some thought, I came up with this crazy thing:

  function wrap (wrappee,wrapper)
     return function (...)
        local cowrapper = coroutine.wrap(wrapper)
        local thruCo = function (...)
            cowrapper(coroutine.yield)
            return ...
        end
        return thruCo( wrappee ( thruCo(...) ) )
     end
  end

That keeps everything on "the stack".  It cheats by creating a new stack!  
But hey, it's late, and that's close enough for me.

Anyone else have an interesting take on this problem?

-Bret