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 1:26 am GMT (diff)