Custom Operators

lua-users home

Lua has a predefined set of operators [1] with no built-in ability to define custom operators beyond this. Nevertheless, there are ways to approximate custom operators. Many of these solutions are not that recommendable.

Hack: User-Defined Named Operators #1 (Infix)

Lua provides a small set of operators and a smaller set that you can override. The << operator, commonly used for inserting objects into a output stream in C++, is not one of them. That doesn't mean we can't try. The following code shows a scheme in which we can simulate the definition and use of custom operators in Lua.

-- Custom operator to evaluate (class)
local CustomOp = {}
function CustomOp:__div(b) -- eval full operation.
  return getmetatable(self.a)['__' .. self.op](self.a, b)
setmetatable(CustomOp, {__call =
  function(class, a, op) -- construct left-half of operation.
    return setmetatable({a = a, op = op}, CustomOp)
function enable_custom_ops(mt) -- enable custom ops on metatable.
  function mt:__div(op)
    return CustomOp(self, op)
  return mt

-- Output stream (class)
ostream  = {}
ostream.__index = ostream
function ostream:write(s)
ostream['__<<'] = function(self, s)  -- '<<' operator
  return self
setmetatable(ostream, {__call =
  function(class, file) -- construct output stream
    file = file or io.output()
    return setmetatable({file = file}, ostream)
cout = ostream()
endl = "\n"  -- end of line

-- example usage

local _ = cout /'<<'/ "hello" /'<<'/ endl

--DavidManura, 200703

Hack: User-Defined Named Operators #2 (Infix)

This mimicks a similar [Python hack]:

local sm = setmetatable
local function infix(f)
  local mt = { __sub = function(self, b) return f(self[1], b) end }
  return sm({}, { __sub = function(a, _) return sm({ a }, mt) end })

local shl = infix(function(a, b) return a*(2^b) end)

print(5 -shl- 4)
--> 80

Cute, huh? Drawback: one table allocation per operation.

--MikePall, 2007-03-09

Hack: User-Defined Named Operators #3

local function factorial(n)
  local y = 1
  for i=2,n do y = y * i end
  return y

local function xor(a,b)
  assert(a == 3 and b == 4) -- an exercise for the reader!
  return 7                  -- or see

debug.setmetatable(0, {  -- create metatable for numbers
  __call = function(a, op)
   if op == '!' then return factorial(a)
   elseif op == 'xor' then return function(b) return xor(a,b) end

print(- (5)'!' + 1, - (3) 'xor' (4)) --> -119    -7

Note the precedence of operators: these are really function calls.

In the case of the unary postfix operators, there is no memory allocation, but there is for the binary op. We might improve that as follows (though unfortunately this is probably now relying on undefined behavior):

local savea
local function xorhelper(b)
  local a; a, savea = savea, nil
  return xor(a,b)
debug.setmetatable(0, {
  __call = function(a, op)
   if op == '!' then return factorial(a)
   elseif op == 'xor' then savea = a; return xorhelper

--DavidManura, 2007-07-14

See Also

RecentChanges · preferences
edit · history
Last edited May 2, 2009 1:26 am GMT (diff)