[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Determining which functions to call
- From: RLake@...
- Date: Tue, 21 Jan 2003 14:17:25 +0000
Here is another approach which uses Lua's amazing
tables-are-functions-are-tables worldview. Here I assume that it is ok to
memoise the result of function calls (which I think works in the case you
used as an example.)
The basic idea is that the object has a number of property fields which may
or may not be present. Each one has an associated function defined in terms
of other field(s). We assume that no function will return "false"; some
other marker value could be used but it would be uglier. The marker is
necessary to avoid endless recursion and to identify whether computations
have the necessary information to proceed or not.
Then we can define everything in terms of an __index metamethod:
function try_to_compute(table, key)
local func = getmetatable(table)[key]
if func then
table.key = false -- mark goal
local val = func(table) -- try to get the value
if val
then table.key = val -- got it, so record it
return val -- and return it
else table.key = nil -- nope, reset for next try
return nil
end
end
end
Note that we use the metatable also for the functions. To set up an
object, we need to attach the metatable, and we need to include the
above function as the __index method. So here we go:
function Searcher(props, funcs)
funcs.__index = try_to_compute
return setmetatable(props, funcs)
end
If I were doing this in real life, I would put the definition of
try_to_compute in Searcher and use a closure instead of getmetatable.
I haven't tried this, but the basic idea would be (my math is a bit rusty
and I'm a bit sleep-deprived, so apologies in advance for typos and stupid
errors.)
do
local funcs = {}
-- example of a property with two possible formula
function funcs.radius(t)
return (t.diameter and t.diameter / 2)
or (t.circumference and t.circumference / 2 * math.pi
end
function funcs.diameter(t)
return t.radius and t.radius * 2
end
function funcs.circumference(t)
return t.diameter and t.diameter * math.pi
end
function funcs.area(t)
return t.radius and t.radius * t.radius * math.pi
end
function Circle(props)
return Searcher(props, funcs)
end
end
a = Circle {radius = 27}
b = Circle {circumference = 40}