local Chain = {}
local Chain_mt = { __index = Chain }
local Invoker = {}
local Invoker_mt = { __index = Invoker }
function Chain:new( ... )
return setmetatable( {
...
}, Chain_mt )
end
function Chain_mt.__call( self, ... )
if not ( ... ) then
return self:run( select( 2, ... ) )
end
return self:append( ... )
end
function Chain:append( ... )
local offset = #self
for index = 1, select( '#', ... ) do
self[ offset + index ] = select( index, ... )
end
return self
end
function Chain:run( ... )
return Invoker:new( self, 1 )( ... )
end
function Invoker:new( chain, index )
return setmetatable({
chain = chain,
index = index
}, Invoker_mt )
end
function Invoker_mt.__call( self, ... )
local chain, index = self.chain, self.index
local link = chain[ index ]
if not link then
return
end
local go = Invoker:new( chain, index + 1 )
local returned = link( go, ... )
if returned then
returned( function ( _, ... )
go( ... )
end )
end
end
--]]
local function newChain( ... )
return Chain:new( ... )
end
return newChain
Not bad, that does look a bit neater. It scored a 2 on that benchmark, same as current version. I'm not sure why it didn't benefit more from eliminating those closures. There's one closure you didn't eliminate:
I tested two other versions of my closure-less solution, one that only eliminates that closure, and one that only eliminates the others. Both benchmarks got knocked down to a 2. I guess you have to be pretty thorough about getting rid of them to get much out of it.