Wednesday, May 22, 2013

Lua Metamethods

Like python's magic methods, Lua allows an object to define its behavior for certain operators. These definitions are simply functions, which are referred to as metamethods. The metamethods are placed as the values of specific keys in an object's metatable. A metatable is an ordinary Lua table. For instance, the metamethod that defines the '+' operator is installed as the value for key __add in the metatable..

In the example below, we create a Lua module that exports a class called Element that represents a value in the finite field of integers modulo 7. This is merely modulo arithmetic. Since the Element class serves as its own metatable, we can simply define the metamethods on the object itself.

finitefield.lua


-- ==============================================
-- finite field of integers modulo prime (7)
-- ==============================================

-- module setup
local modname = ...
local M = {}
_G[modname] = M
package.loaded[modname] = M

-- import section
local error = error
local getmetatable = getmetatable
local setmetatable = setmetatable
local string = string
local tostring = tostring

-- no more external access after this point
setfenv(1, M)

-- private
local MODULO = 7

-- public  
Element = {}

function Element:new(n)
    local o =  {}
    setmetatable(o, self)
    self.__index = self
    o.val = n % MODULO
    return o
end

function Element:__tostring()
    return string.format("%d", self.val)
end

function Element:__concat(s)
    return tostring(self) .. tostring(s)
end

function Element:__add(other)
    if getmetatable(other) ~= getmetatable(self) then
        error("attempt to 'add' an element with a non-element")
    end
    local val = self.val + other.val
    return Element:new(val)
end

function Element:__mul(other)
    if getmetatable(other) ~= getmetatable(self) then
        error("attempt to 'multiply' an element with a non-element")
    end
    local val = self.val * other.val
    return Element:new(val)
end

function Element:__lt(other)
    return self.val < other.val
end

function Element:__lt(other)
    return self.val < other.val
end

function Element:__eq(other)
    return self.val == other.val
end

example


#!/usr/bin/env lua

local ff = require 'finitefield'

local a = ff.Element:new(5)
local b = ff.Element:new(8)
    
local c = a + b 
print(a .. ' + ' .. b .. ' = ' .. c)

local d = a * b 
print(a .. ' * ' .. b .. ' = ' .. d)

output


5 + 1 = 6
5 * 1 = 5

No comments:

Post a Comment