[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: RE: Functions prototypes and real #defines
- From: RLake@...
- Date: Sun, 9 May 2004 18:48:58 -0400
Interesting discussion. I have been
looking at ways to implement the "visitor" pattern in Lua, and
my benchmarks look pretty similar.
Quinn's formulation:
> function traverse(N)
> return
traversal_table[N:GetRuleName()](N);
> end
obviously improves readability, but
at the expense of an extra function call; in a simple evaluation benchmark
(code is at http://lua-users.org/files/wiki_insecure/users/rici/traverse.lua),
manually inlining this function call gave a saving of about 20%.
One can also give traversal_table a
__call metamethod, and thereby avoid having two objects to deal with; this
might or might not be worth the extra 5% cost.
A functional tuples-like implementation
is almost as fast as the inlined traverse-call, and almost as readable
as the standard traverse function, so it might be worthwhile. I did not
try benchmarking with tuples-in-c, as per the discussion from last month,
but I suspect it would slightly speed up the functional tuples implementation,
making that the fastest.
The careful reader will notice that
the standard OO-with-metatables pattern is not part of this benchmark.
It didn't satisfy one of my requirements, which is that you should be able
to implement new temporary visitors without namespace issues.
The benchmark is runnable from the above
URL, but to give a feeling for how the code looks (the names refer to the
benchmark description below), these are the first couple of lines of each
mechanism, dealing with the "plus" operator:
"switcher":
local eval, evaltab = switcher"eval"
function evaltab:plus() return
eval(self.a) + eval(self.b) end
"ugly switcher":
local evaltab = errtable"eval"
function evaltab:plus()
local a, b = self.a, self.b
return evaltab[a.op](a)
+ evaltab[b.op](b)
end
"metatable" (here self refers
to the visitor object, not the visited object)
evalmeta = traverser"eval"
function evalmeta:plus(obj) return
self(obj.a) + self(obj.b) end
"if-then-else"
local function eval(self)
local op = self.op
if
op == "plus" then return eval(self.a) + eval(self.b)
"functional tuples":
local feval = errtable"eval"
function feval.plus(a, b) return
a(feval) + b(feval) end
And benchmark results on one of my machines
(the other one is consistent, but slower):
rlake $ lua traverse.lua 1000000
These should all look the same:
(set c (+ (/ 21 a) (* b (- 10 (_ b)))))
42
(set c (+ (/ 21 a) (* b (- 10 (_ b)))))
42
(set c (+ (/ 21 a) (* b (- 10 (_ b)))))
42
(set c (+ (/ 21 a) (* b (- 10 (_ b)))))
42
(set c (+ (/ 21 a) (* b (- 10 (_ b)))))
42
Evaluate the _expression_ 1000000 times
using switcher took 11.48 seconds
using ugly switcher took 9.02 seconds
using metatable took 12.09 seconds
using if-then-else took 11.85 seconds
using functionals took 9.38 seconds