Setting addition operator through metatable in Lua

331 views Asked by At
vals = { i=1, j=2}

setmetatable(vals, {
  __add = function (a, b)
    return a*b
  end,
    
})

sr = vals.i+vals.j
print(sr)

It prints sr as 3. The expected answer is 2 as 1*2 equals to 2. Why the addition operation (metamethod) is not getting into picture from the metatable of vars?

2

There are 2 answers

0
스피겔 빈 On

the first argument of the __add method is table type

local vals = {
    i = 1,
    j = 2
}

setmetatable(
    vals,
    {
        __add = function(tbl, value)
            return tbl.i + tbl.j + value
        end
    }
)

print(vals + 13)
0
koyaanisqatsi On

You misunderstood that a table with a metatable only fires at the table.
...not at a key/value it holds with same or different datatype.
They have not inherited the metatable.
Exception: Own implemention with __newindex
Where you can add/share the parent metatable to a new table (child then )

So look at this code and try it by yourself and understood...

vals = setmetatable({i = 1, j = 2}, {
  __add = function (left, right)
    return left.i * right -- Little change here
  end,
    
})

vals + 15 -- __add will trigger this and returning: 15
vals + vals.j -- __add will trigger this and returning: 2
-- Lets change vals.i
vals.i = vals + vals.j
vals + 15 -- __add will trigger this and returning: 30
vals + vals.j -- __add will trigger this and returning: 4

"Numbers do not have metatables."
The datatype string has.

for key, value in pairs(getmetatable(_VERSION)) do
  print(key, "=", value)
end
__div   =   function: 0x565e8f80
__pow   =   function: 0x565e8fa0
__sub   =   function: 0x565e9000
__mod   =   function: 0x565e8fc0
__idiv  =   function: 0x565e8f60
__add   =   function: 0x565e9020
__mul   =   function: 0x565e8fe0
__index =   table: 0x5660d0b0
__unm   =   function: 0x565e8f40

And the __add is somewhat broken or not really useable...

_VERSION + 3
stdin:1: attempt to add a 'string' with a 'number'
stack traceback:
    [C]: in metamethod 'add'
    stdin:1: in main chunk
    [C]: in ?
_VERSION + "3"
stdin:1: attempt to add a 'string' with a 'string'
stack traceback:
    [C]: in metamethod 'add'
    stdin:1: in main chunk
    [C]: in ?

Imagine numbers have all math functions as methods...

> math.pi = debug.setmetatable(math.pi, {__index = math})
-- From now every number has math methods
> print(math.maxinteger:atan2() * 2)
3.1415926535898
-- Using method on return of before used method
-- Maybe it should be called "Chaining methods"?
> print(math.pi:deg():tointeger():type())
integer
-- type() returns a string. - Lets use upper() on this...
> print(math.pi:deg():tointeger():type():upper())
INTEGER
-- Typed in  a Lua interactive console ( _VERSION = 5.4 )
-- PS: Also random() is not far away and can be
-- used directly with a number for a dice roller with
> print((1):random(6))
1
> print((1):random(6))
5
> print((1):random(6))
5
> print((1):random(6))
4
-- ;-)

Oups, how easy is this?