Search code examples
c++clualua-apimetatable

Lua Meta Event Argument Order


I'm using the Lua API to override meta-events for my own C++ objects wrapped as userdata. However, some meta-events can take multiple arguments that may be userdata or regular values which I can convert to a userdata. For example, __add, __eq, __concat, etc.

Firstly, for these meta-events, whose __add gets called if I add together two userdata, and does it only get called once? This is relevant if I have two DIFFERENT types of userdata with different __add hooks (although it would be bad practice for them to have different return results).

Secondly, for an example like this: 2 + userdata instead of userdata + 2, is there a guarantee that the userdata will always show up first on the stack? This will make my implementation significantly more straightforward, and I haven't found much documentation on the detailed behavior of meta-events besides __index.

Lastly, what is Lua's behavior if you add multiple objects? From tests with metatables NOT using the C API, it seems like PEMDAS ordering. I.e. userdata1 + 3 + userdata2 + userdata3 + nonuserdata, but I've found no reference to confirm this. Does __add only get called once with all arguments on the stack, calling the __add of the first userdata, or does it propagate from one direction creating temporary rvalues?

Here is an example of how I take args from the stack for __arg, which is straightforward if the order of arguments is guaranteed.

    if (unlikely(lua_gettop(L) != 2))
    {
        return LUA_FAILURE;
    }

    Val *v = CheckLuaUserdata(L, 1);
    if (unlikely(!v))
    {
        return LUA_FAILURE;
    }

    bool allocated = false;
    Val *arg2 = lua_mgr->PullLuaValFromGenericArg(L, 2, &allocated);
    if (unlikely(!arg2))
    {
        return LUA_FAILURE;
    }

Solution

  • First: The left one. In the case of A + B, A's __add is called.

    Second: Nope, sorry. The arguments are passed in order (left will stay left, right will stay right)

    http://lua-users.org/wiki/MetatableEvents

    Finally: I'm not entirely certain. I seriously doubt it calls __add with all of them, and I would suspect it moves from left to right (following the order of operations in math). It certainly follows order of operations for 1 + 1 / 2.