Custom Operators |
|
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
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
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
cond ? expr1 : expr2
construct in C