Question

I need to create a structure. The structure must contain an array of "boolean conditions". Something like this:

function ReturnStructure ()
    local structure = { 
        {A < 10},
        {B == "smth"},
        {FunctionReturnsTrueOrFalse(params)},
        --... 
    }   
    return structure
end

structure = ReturnStructure()

print(structure[1][1]) -- prints true or false depending on the value of A

In fact these tables contain true or false, not conditions, because when we call function ReturnStructure and it creates a local table structure, all conditions in the fields will be executed. I want to create a structure whose fields will contain not boolean values, but something that I can execute (when I want to do it) and get a boolean value. I can achieve this by using anonymous functions:

function ReturnStructure ()
    local structure = { 
        {function() return A < 10 end},
        {function() return B == "smth" end},
        {FunctionReturnsTrueOrFalse, params}, -- I don't call function in this line, a just put its adress and parameters to table.
        --... 
    }   
    return structure
end

structure = ReturnStructure()

print(structure[1][1]) -- prints function: 0x109bdd0
print(structure[1][1]()) -- prints true or false. I execute condition in this string.

So, there is a code which works as I want it to, but it seems very ugly. I want to hear some ideas on how to create a simpler and more beautiful table, without printing function () return ... in every field. I think that I should use a simple OOP implementation to create my structure as an object, but I don't know how to do it. I also will be happy to get some references to methods, implementations, articles etc., which can help me to find some ideas.

Was it helpful?

Solution

I want to hear some ideas on how to create a simpler and more beautiful table, without printing function () return ... in every field.

There aren't. If Lua had C#'s lambda syntax, you could write:

local structure = { 
    () => A < 10,
    () => B == "smth",
    () => FunctionReturnsTrueOrFalse(params),

But Lua likes to keep things small and simple, to avoid adding size and complexity to the language and its implementation, so we have one syntax for one function type.

You could store them as strings, then compile and run them later, but that's choosing form over function. You don't want to be invoking the compiler unnecessarily.

local structure = { 
    'A < 10',
    'B == "smth"',
    'FunctionReturnsTrueOrFalse(params)',

So your original solution is better. I don't particularly like the way that the first two items defer evaluating their arguments, while your third example evaluates the parameters at compile time. It would be more consistent to treat the FunctionReturnsTrueOrFalse the same

local structure = { 
    function() return A < 10 end,
    function() return B == "smth" end,
    function() return FunctionReturnsTrueOrFalse(param1) end,

This also means you don't need to put them in tables. Each is just a function you call, which simplifies the calling code as well.

If you really wanted to evaluate FunctionReturnsTrueOrFalse's arguments at compile time, I'd write a utility routine to build a closure from a function and its arguments:

local function bind(f, ...)
    local args = {...}
    return function() f(unpack(args)) end
end

Then use that to bind the function to its args:

local structure = { 
    function() return A < 10 end,
    function() return B == "smth" end,
    bind(FunctionReturnsTrueOrFalse, param1, param2, param3),

Then everything in your table is simply a function so you don't need special handling

OTHER TIPS

function ReturnStructure ()
   local structure = {
     {'A < 10'},
     {'B == "smth"'},
     {FunctionReturnsTrueOrFalse, 'parameter'},
   }
   local function call_me(f, ...)
      return (type(f)=='function' and f or 
         assert((load or loadstring)('return '..f)))(...)
   end
   return setmetatable({}, {
      __index =
         function(t,k)
            if structure[k] then
               return call_me((table.unpack or unpack)(structure[k]))
            end
         end,
      __newindex = function(t,k,v) structure[k] = v end
   })
end

A = 2
B = "anything"
function FunctionReturnsTrueOrFalse(par)
   return #par > 5
end

structure = ReturnStructure()

print(structure[1])  -- true
print(structure[2])  -- false
print(structure[3])  -- true
structure[4] = {'1==0'}
print(structure[4])  -- false
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top