Let's talk about more than just the code generation approach! As in the question, consider the need of a function:
function (x, y)
return x.field1 --[[ < or >= ]] y.field1
end
For the sake of the examples assume that we have global variables:
FIRST = {field1 = 3}
SECOND = {field1 = 5}
Branching
The simplest solution (perhaps also the most typical?) that comes to my mind is a verbose if:
function foo (x, y, o)
if o == nil or o == "asc" then
return x.field1 < y.field1
end
if o == "dsc" then
return x.field1 >= y.field1
end
error("Unknown option")
end
-- Example:
foo(FIRST, SECOND, "asc")
foo(FIRST, SECOND, "dsc")
Note that early returns make else unnecessary in this case but it might not always be true.
Anonymous function
But, hey, what's that? What if rather than a string option we pass something more bizarre like... something that can be called? Let's go with a simple function this time:
local asc = function (a, b) return a < b end
local dsc = function (a, b) return a >= b end
function bar (x, y, compare)
compare = compare or asc
return compare(x.field1, y.field1)
end
-- Example:
bar(FIRST, SECOND, asc)
bar(FIRST, SECOND, dsc)
bar(FIRST, SECOND, function (a, b) return a < b end)
Higher-order function
The previous example doesn't really look that good with a such simple operation, but let's take it as a base and let's create a function that will return us the desired function:
function make (compare)
return function (x, y) return compare(x.field1, y.field1) end
end
-- Example:
local asc = make(function (a, b) return a < b end)
local dsc = make(function (a, b) return a >= b end)
asc(FIRST, SECOND)
dsc(FIRST, SECOND)
Actual generation
Now then, let's try something closer to code generation. Lua gives us the ability to load chunks as we go with load* function family.
Please note that load in 5.1 is different from load in 5.2 or load in 5.3. In 5.1 you want to use loadstring instead of load.
function generate (op)
return load(string.format("return function (x, y) return x.field1 %s y.field1 end", op))()
end
-- Example:
local asc = generate("<")
local dsc = generate(">=")
asc(FIRST, SECOND)
dsc(FIRST, SECOND)
x.field1is same asx['field1'], which is easier to alter programmatically.