FortuneCookie101
FortuneCookie101

Reputation: 525

Lua metatable, how to forward undefined functions?

I have an empty table which I want to act as a "gateway" to another set of functions at another location.

tbl = {}

I want to pass called functions from this table to somewhere else as a string:

tbl.someMethod("hello")

I've tried this with limited success.

hand = {
    __index = function(tbl, name)
      hand[name] = function(...) 
          passToSomewhere(name, ...)
      end
    end,
    __call = function(tbl, name, ...)
        hand[name](...)
    end
}
setmetatable(tbl, hand)
tbl.someFunction("hello!", someTbl, someNumber)

How do I forward the undefined function through the table without it throwing errors?

Edit: More detail

I'm trying to define and call a function in a table in one call:

tbl = {}

hand = {
  __index = function(tbl, name)
    print(name)
    tbl[name] = function(...)
      print(...)
    end
  end
}
setmetatable(tbl, hand)

s,e = pcall(tbl.help,"banana","goat")
print(s)

s,e = pcall(tbl.help,"banana","goat")
print(s)

This code does work but the first pcall will throw an error because the function hasn't been defined yet.

Say I wanted to use an library which I know updates quite a lot and keep my script compatible and this library may not be present on my computer. I would like to forward calls to this library across some interface but I still want to be able to call the functions in the same way.

--For example I would like to call this function like this:
someLib.doSomething(name, age, telephone)

--Instead of passing it through another function:
someOtherLib.invoke("someLib.doSomething", name, age, telephone)

Is this possible?

Edit 2:

Thanks @greatwolf !

This is my working test code.

tbl = {}

hand = {
  __index = function(tbl, name)
    tbl[name] = function(...)
      return print(name, ...)
    end
    return rawget(tbl, name) 
  end
}
setmetatable(tbl, hand)

tbl.help("banana","goat")

Upvotes: 3

Views: 457

Answers (1)

greatwolf
greatwolf

Reputation: 20848

Okay, based on your updated details you want lua to translate this call

someLib.doSomething(name, age, telephone)

into

someOtherLib.invoke("someLib.doSomething", name, age, telephone)

behind the scenes. What you have is almost there, you just need to return the newly created function back:

__index = function(tbl, name)
  tbl[name] = function(...)
    return someOtherLib.invoke("someLib."..name, ...)
  end
  -- return tbl[name] works too, I used rawget to indicate 
  -- no further __index lookup should be done
  return rawget(tbl, name) 
end

Now, if your someOtherLib is just a table of functions, lhf's suggestion will work too

setmetatable(tbl, {__index = someOtherLib})

Now if your someOtherLib provides someway to get the function you want to call without actually invoking it just yet, __index can relay this without creating extra closure wrappers

__index = function(tbl, name)
  tbl[name] = someOtherLib.getFuncByName(name)
  return tbl[name]
end

The __call metamethod is not needed here.

Upvotes: 3

Related Questions