lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Luis Carvalho <carvalho <at> dam.brown.edu> writes:
> Is there any reason why __eq is not called when the metatable is
> shared for a type other than table and userdata?...
> it should be at least stated in the manual.

I think you're right about the manual where it says "eq" is defined as

     function eq_event (op1, op2)
       if type(op1) ~= type(op2) then  -- different types?
         return false   -- different objects
       end
       if op1 == op2 then   -- primitive equal?
         return true   -- objects are equal
       end
       -- try metamethod
       local h = getcomphandler(op1, op2, "__eq")
       if h then
         return h(op1, op2)
       else
         return false
       end
     end

However, the source code for luaV_equalval shows that a primitive equal ("return
op1 == op2") is also always done for all types other than tables and userdata. 
2.5.2 comments on this ('You can change the way that Lua compares tables and
userdata by using the "eq" metamethod (see §2.8)'), but it's not explicit.

The general rule for all this is summarized, I think, more clearly in PiL2,
13.4: "The metamethods for arithmetic and relational operators all define
behavior for otherwise erroneous situations.  They do not change normal behavior
of the language [though tables do allow this]"  Here, 3==4 and 3+4 are already
defined in the language, so metamethods are not called for them.  Beginning Lua
Programming (Chap 8) also has a good table "Metamethod Applicability" that
summarizes when metamethods apply or not.

I've thought the reason for this partly has to do with constant folding.  (3+4)
is evaluated at compile time, and metamethods don't exist then:

$ echo "return (3+4)" | luac -p -l -

main <stdin:0,0> (3 instructions, 12 bytes at 0x671200)
0+ params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions
        1       [1]     LOADK           0 -1    ; 7
        2       [1]     RETURN          0 2
        3       [1]     RETURN          0 1

Interestingly, 3==4 in particular is not constant folded (but maybe could be?)

$ echo "return (3==4)" | luac -p -l -

main <stdin:0,0> (6 instructions, 24 bytes at 0x671200)
0+ params, 2 slots, 0 upvalues, 0 locals, 2 constants, 0 functions
        1       [1]     EQ              1 -1 -2 ; 3 4
        2       [1]     JMP             1       ; to 4
        3       [1]     LOADBOOL        0 0 1
        4       [1]     LOADBOOL        0 1 0
        5       [1]     RETURN          0 2
        6       [1]     RETURN          0 1


> What about functions? I can understand why you don't have
> individual metatables for functions

I actually recently came across a case where I thought that would be useful.

You can implement objects with functions rather than tables.  This is
particularly convenient for callable objects.  However, you can't add fields to
that object without overwriting the "global" metatable for functions (e.g. as in
http://lua-users.org/wiki/MutableFunctions ) or converting it to a table.

Whether that is anything more than "nice to have in theory" though, I don't know.

> I'm all for __eq (and other comparisons for that
> matter) being more "consistent". 

In the words of someone else, Lua is not "fully virtualizable": 
http://lua-users.org/wiki/LuaVirtualization .  This causes issues of various
severity, with __len being one of the more major ones.

I think part of Lua's philosophy is to make design trade-offs at times when
efficiency matters in the common case.  Another recent example of that is how
concatenation is right-associative and limited to approximately 200 operands --
http://lua-users.org/wiki/AssociativityOfConcatenation -- when it otherwise
seems to make sense in theory for it to be left associative like most everything
else.