Home Explore Blog CI



neovim

16th chunk of `runtime/doc/luaref.txt`
802c32036e3c15cc04fb8d847f9b73cce81686fed0d35df10000000100000fa0
 single metatable for all
numbers, and for all strings, etc.

A metatable may control how an object behaves in arithmetic operations, order
comparisons, concatenation, length operation, and indexing. A metatable can
also define a function to be called when a userdata is garbage collected. For
each of those operations Lua associates a specific key called an event. When
Lua performs one of those operations over a value, it checks whether this
value has a metatable with the corresponding event. If so, the value
associated with that key (the metamethod) controls how Lua will perform the
operation.

Metatables control the operations listed next. Each operation is identified by
its corresponding name. The key for each operation is a string with its name
prefixed by two underscores, `__`; for instance, the key for operation "add"
is the string "__add". The semantics of these operations is better explained
by a Lua function describing how the interpreter executes that operation.

The code shown here in Lua is only illustrative; the real behavior is hard
coded in the interpreter and it is much more efficient than this simulation.
All functions used in these descriptions (`rawget`, `tonumber`, etc.) are
described in |lua-lib-core|. In particular, to retrieve the metamethod of a
given object, we use the expression
>
       metatable(obj)[event]
<
This should be read as
>lua
       rawget(metatable(obj) or {}, event)
<
That is, the access to a metamethod does not invoke other metamethods, and the
access to objects with no metatables does not fail (it simply results
in `nil`).

"add":                                                                 *__add()*
------
the `+` operation.

The function `getbinhandler` below defines how Lua chooses a handler for a
binary operation. First, Lua tries the first operand. If its type does not
define a handler for the operation, then Lua tries the second operand.
>lua
       function getbinhandler (op1, op2, event)
         return metatable(op1)[event] or metatable(op2)[event]
       end
<
By using this function, the behavior of the `op1 + op2` is
>lua
       function add_event (op1, op2)
         local o1, o2 = tonumber(op1), tonumber(op2)
         if o1 and o2 then  -- both operands are numeric?
           return o1 + o2   -- `+` here is the primitive `add`
         else  -- at least one of the operands is not numeric
           local h = getbinhandler(op1, op2, "__add")
           if h then
             -- call the handler with both operands
             return h(op1, op2)
           else  -- no handler available: default behavior
             error(...)
           end
         end
       end
<
"sub":                                                                 *__sub()*
------
the `-` operation. Behavior similar to the "add" operation.

"mul":                                                                 *__mul()*
------
the `*` operation. Behavior similar to the "add" operation.

"div":                                                                 *__div()*
------
the `/` operation. Behavior similar to the "add" operation.

"mod":                                                                 *__mod()*
------
the `%` operation. Behavior similar to the "add" operation, with the
operation `o1 - floor(o1/o2)*o2` as the primitive operation.

"pow":                                                                 *__pow()*
------
the `^` (exponentiation) operation. Behavior similar to the "add" operation,
with the function `pow` (from the C math library) as the primitive operation.

"unm":                                                                 *__unm()*
------
the unary `-` operation.
>lua
       function unm_event (op)
         local o = tonumber(op)
         if o then  -- operand is numeric?
           return -o  -- `-` here is the primitive `unm`
         else  -- the operand is not numeric.
           -- Try to get a handler from the operand
           local h = metatable(op).__unm

Title: Lua Metamethods for Arithmetic Operations
Summary
This section details how Lua metatables control arithmetic operations (+, -, *, /, %, ^, unary -). It explains that each operation is associated with a specific event (e.g., '__add' for addition). It presents a Lua function `getbinhandler` that determines the handler for binary operations by checking the metatables of the operands. If a metamethod is found (e.g., `__add`), it's called to perform the operation; otherwise, an error occurs. The code illustrates how Lua simulates these operations, emphasizing that the real behavior is hardcoded for efficiency. The example includes how Lua handles binary operations when one or both operands are non-numeric.