Custom Operators


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 1, 2009 8:26 pm GMT (diff)

AltStyle によって変換されたページ (->オリジナル) /