Lua metatables and metamethod - How to call a different member function

天涯浪子 提交于 2019-12-02 02:33:15

Response to updated post:

progress_object is passed as first argument to showSum. But i need group_object to be passed

If you're going to ignore the state of the object a method is called on, and substitute the state of some other object, why is it even a method on that object? That's like overriding the addition operator to do multiplication, a recipe for confusion.

In other words, you want this:

progress_object:method("foo")

To resolve, via bizarre internal machinery, into this:

group_object:method("foo")

Why not skip a step and just make the latter call?

If you must, you could achieve this by returning a proxy for the method which replaces self with __group

local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self,key)
  local groupval = self.__group[key]
  if key == '__group' or not groupval then
    return rawget(self,key)
  elseif type(groupval) ~= 'function' then
    return groupval
  else
      return function(...)
        if self == ... then -- method call
          -- replace self argument with __group
          return groupval(self.__group,select(2,...))
        else
          return groupval(...)
        end
      end
  end
end

Response to original post:

How I am trying to do the same for member functions. i.e If I calltable:key() a lookup must be performed in table.__group and if the function is present, then table.__group:key() should be called.

How do I accomplish this?

Do nothing. Your original code handles this.

Lua doesn't know what a "member function" is. A member is a member (i.e. an element in a table), and whether the value of that member is a function is irrelevant.

Remember:

  1. obj:method(a,b,c) is exactly equivalent to obj.method(obj,a,b,c)
  2. obj.method is exactly equivalent to obj["method"].
  3. Your code already resolves obj["method"] into obj.__group["method"]

So you're done.

For instance, say we have:

group = {}
function group:showSum    (a,b) print(a + b) end
function group:showProduct(a,b) print(a * b) end

Using your first code, we can write:

foo = setmetatable({__group = group}, PROGRESS)

foo:showSum(3,3) -- 6
foo:showProduct(3,3) -- 9

That's it.



Now, as long as we're here, let's look at what your second function is doing:

     local val = self.__group[key]
     if type(val) == "function" then 
         self.__group:val()
         return function() end 
     end

First you grab the function value from __group. At this point you're done. Simply return that value, and the caller is going to call that value (i.e. (...)). Instead, you call __group["val"] which is likely a totally different function from __group[key] (unless key=="val"), then you pass the caller a function which does nothing.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!