lua-users home
lua-l archive

Fun with function wrapping

[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

AltStyle によって変換されたページ (->オリジナル) /