In Lua, how can I know if a table contains a class function?

Go To StackoverFlow.com

2

Say I declare a lua function using the : operator like so:

function ClassName:myFunc( stuff )
    --do stuff
end

And then say I store that function in a table like so:

someTable = {
    ClassName.myFunc,
    someGlobalFunc,
} 

And then, say I have another function that goes through the table and attempts to call the given functions.

function ClassName:callStuffInThisTable(table)
    -- I go through the table, which might be someTable above, and call all the functions
end

My question is, how do I know if a function in the table is owned by ClassName, so that I can call it using self?

2012-04-04 23:19
by Charles Randall
Out of curiosity, why are you wanting/needing to call all of the functions in a given table, that you can't also mandate that all of those functions either all be class methods or all be bare functions - Amber 2012-04-04 23:32


7

You don't. At least, Lua isn't going to tell you.

function ClassName:myFunc( stuff ) is just syntactic sugar as far as Lua is concerned. It's no different from this: ClassName.myFunc = function (self, stuff). The functions are equivalent. Likewise for the : call syntax, ClassName:myFunc(stuff) is semantically equivalent to ClassName.myFunc(ClassName, stuff).

It is up to you to know what your functions are and what they do. This requires coding discipline. If you have a list of functions that you need to call in a loop, then they should be designed to be called with the same parameters.

There are two ways to do this. One way is to make all of the functions "class functions":

someTable = {
    ClassName.myFunc,
    function(self, ...) return someGlobalFunc(...) end,
} 

This way, the self parameter is ignored. Obviously, you could create a special function table object that has functions for inserting "global" functions into the table that will automatically generate the wrapper:

function insertFuncIntoTable(self, func)
  self[#self + 1] = function(self, ...) func(...) end
end

insertFuncIntoTable(someTable, someGlobalFunc)

Note: there is a difference between these, assuming "someGlobalFunc" is actually a member of the global table (rather than a local). This version will take the value that _G["someGlobalFunc"] currently has, just as your original code does. However, the first version takes the value that it has at the time it is called, which may be a different function from the one it was at the time someTable was created.

So this version is safer.

Alternatively, you can make it so that any "class functions" in the table are explicitly bound to an object instance:

someTable = {
    function(self, ...) ClassName.myFunc() end,
    function(self, ...) return someGlobalFunc(...) end,
} 

BTW, in general, if you declare a function using : syntax, you're supposed to use that function that way, via instance:myFunc(...). Obviously it's just a Lua function like any other, so you can do what you like. But misuse can make understanding what's going on harder.

Lua affords you a lot of power. But you're still required to exercise judgement and discipline when coding. Lua will not save you from yourself (entirely).

2012-04-04 23:36
by Nicol Bolas
Thanks for the insight. The leap I was failing to make was that since functions are anonymous, their names don't have any meaning.

Ultimately what I'm trying to do is make a script that iterates through functions and parameters, waiting when necessary, and so I'm doing this:

script = { 
{ func, { params } },
}

Ideally though I'd have user functions and pre-implemented functions. I can easily pass a self object, I was just trying to be clever - Charles Randall 2012-04-05 01:11



0

One way to tell if the function is "owned" by ClassName would be to scan and check.

ClassName = {}
function ClassName:fn(self) ... end

t = { function() ... end , ClassName.fn() }

function has_value( klass, value )
  for k,v in pairs(klass) do
    if v==value then return true
  end
  return false

function ClassName:callStuffInThisTable(table)
  for k,v in pairs(table) do
    if has_value(ClassName, v) then
      v(self)
    else
      v()
    end
  end
end

This has O(n^2) behaviour though due to the table scan. We can reduce this to O(n log(n)) ) by using the functions in ClassName as a new table

function ClassName:callStuffInThisTable(table)
  local t = {}
  for k,v in pairs(ClassName) do
    t[v] = 1
  end

  for k,v in pairs(table) do
    if t[v]==1 then
      v(self)
    else
      v()
    end
  end
end   
2012-04-05 01:16
by Michael Anderson
Ads