Custom Operators

lua-users home
wiki

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)
end
setmetatable(CustomOp, {__call =
  function(class, a, op) -- construct left-half of operation.
    return setmetatable({a = a, op = op}, CustomOp)
  end
})
function enable_custom_ops(mt) -- enable custom ops on metatable.
  function mt:__div(op)
    return CustomOp(self, op)
  end
  return mt
end

-- Output stream (class)
ostream  = {}
ostream.__index = ostream
enable_custom_ops(ostream)
function ostream:write(s)
  io.write(s)
end
ostream['__<<'] = function(self, s)  -- '<<' operator
  self:write(s)
  return self
end
setmetatable(ostream, {__call =
  function(class, file) -- construct output stream
    file = file or io.output()
    return setmetatable({file = file}, ostream)
  end
})
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 })
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
end

local function xor(a,b)
  assert(a == 3 and b == 4) -- an exercise for the reader!
  return 7                  -- or see http://lua-users.org/wiki/BitUtils
end

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
   end
  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)
end
debug.setmetatable(0, {
  __call = function(a, op)
   if op == '!' then return factorial(a)
   elseif op == 'xor' then savea = a; return xorhelper
   end
  end
})

--DavidManura, 2007-07-14

See Also


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