luaoperatorslua-tableevaluation# Using metatables for adding two different types

I have fractions table which stores fractions and fractions get associated with its metatable. `fraction.add`

is metaoperation (`__add`

).
Here is the problem. I want to evaluate x + y.

If x and y are both fractions then there is no issue in evaluating it. It gets evaluated with`farction.add`

.

If both x and y are numbers, which are not fractions, then it is simple addition of numbers, which has nothing to do with fractions.

If x is fraction and y is non-fraction number (or vice-versa), then I want to convert fraction x into number and add it to y. I of course can easily convert fraction into number, but the problem is with `__add`

metatable of fraction which is associated with `fraction.add`

. It works only when both x and y are fractions. It throws error as y is not fraction. So I am looking for the logic that will handle the case when one is fraction and other is non-fraction number. It probably is simple if else in metatable, but I am not able to do it. Any ideas would really be helpful.

Solution

I've implemented a full-fledged such `fraction`

"class" with support for this. It's as simple as checking the types of the arguments `a, b`

of the `__add`

metamethod and converting them to fractions if needed.

Or, for a more minimal example, which skimps on a couple points:

- Fractions aren't shortened. Float / integer imprecisions / overflows will ultimately result in inaccurate fractions. Ideally you should use some kind of big integers for numerator and denominator, and shorten after every operation.
- For simplicity, only integers will be converted to fraction; floats will raise an error, since converting floats to fractions is more tricky.
- It's missing plenty of operations.

```
local fraction_mt = {}
local function new_fraction(numerator, denominator)
assert(numerator % 1 == 0)
assert(denominator % 1 == 0)
return setmetatable({numerator = numerator, denominator = denominator}, fraction_mt)
end
local function add_fractions(a, b)
-- Note: No care is taken to shorten the resulting fraction here.
return new_fraction(a.numerator * b.denominator + b.numerator * a.denominator,
a.denominator * b.denominator)
end
function fraction_mt.__add(a, b)
if type(a) == "number" then
a = new_fraction(a, 1)
elseif type(b) == "number" then
b = new_fraction(b, 1)
end
return add_fractions(a, b)
end
function fraction_mt:__tostring()
return ("%d/%d"):format(self.numerator, self.denominator)
end
print(new_fraction(1, 2) + new_fraction(1, 2)) -- 4/4
print(new_fraction(1, 2) + 1) -- 3/2
print(1 + new_fraction(1, 2)) -- 3/2
```

Note that Lua will call `__add`

even if only one of the operands is not a number (see the reference manual):

If any operand for an addition is not a number, Lua will try to call a metamethod. It starts by checking the first operand (even if it is a number); if that operand does not define a metamethod for __add, then Lua will check the second operand. If Lua can find a metamethod, it calls the metamethod with the two operands as arguments, and the result of the call (adjusted to one value) is the result of the operation. Otherwise, if no metamethod is found, Lua raises an error.

After clarification: To convert a fraction to a number before adding, producing a number for `fraction + number`

or `number + fraction`

, simply use:

```
function fraction_mt:tonumber()
return self.numerator / self.denominator
end
function fraction_mt.__add(a, b)
if type(a) == "number" then
return a + b:tonumber()
end if type(b) == "number" then
return a:tonumber() + b
end
return add_fractions(a, b)
end
```

- How to debug lua code inside nginx config?
- sending multible inputs to lua-script with subprocess
- How to remove elements inside a table based on a value of those elements?
- Formatting errors when using certain code
- Neovim: icons missing nvim-tree-web-devicons
- Lua not allowing global variables in a table
- Rapid fire with logitech lua script?
- Redis Lua function call failing with CROSSSLOT error
- print call issue in Lua based function
- Redis Function not found
- Reading Redis stream in Lua script
- Get file creation time with lua
- How do I make a wait statement in Lua?
- Lua : attempt to index a nil value; avoiding errors in conditionals
- Pandoc Lua Filter: How to access the title variable?
- How can one implement OO in Lua?
- Add relative line numbers in neo-tree using Lazy in Neovim
- Call string method on string literal
- How to make multi-argument choose function in LuaU?
- How to capture the integer or point number from string?
- How to sum a table of numbers in Lua?
- NeoVim - Check if a Vim function exists from Lua
- Sort points in clockwise order?
- Custom Logarithm Lua (Answer has trick that can be used on almost any language)
- Roblox Luau - Asset refuses to load in-game, but works in studio
- lpeg.Cmt and empty loop body
- Check if point is in convex polygon
- How to bind a luafunction to keypress in vim
- Can I force Lua's table indexing to start from zero?
- Retrieve the returned value of an execution