. You do this with a statement of the
form
. The function
otherwise.
Actually every kind of value can have a metatable, but
apart from tables they can only be set at the API level.
If the metatable of an object has a key that is the name of an event,
prefixed by two underscores, then the corresponding value of the metatable
is taken as a function for interpreting the event. This is easiest to
understand by example.
Gaussian integers are complex numbers whose real and imaginary parts
are integers. We could represent one as
z = { re = x; im = y; }
In that case, addition and multiplication would be given by
complex_add = \(z,w)
=> {
re = z.re + w.re;
im = z.im + w.im;
}
end
complex_mul = \(z,w)
=> {
re = z.re * w.re - z.im * w.im;
im = z.re * w.im + z.im * w.re;
}
end
If we define
complex_mt = {
__add = complex_add;
__mul = complex_mul;
}
and set this as the metatable for the tables that we deem
to represent Gaussian integers then we will be able to use
the standard operators
+ and
* with them. So we define
GaussInt = \(x,y)
local z = { re = x; im = y }
setmetatable(z,complex_mt)
=> z
end
Of course, a bit more detail should be added so that we
can treat numbers as Gaussian integers (test the type of
the arguments in
complex_add and
complex_mul ), and so that
Gaussian integers are displayed prettily (use the
tostring event). I hope the general idea is clear.
To see how prettyprinting of complex numbers is not
entirely straightforward, here is a program to run in a
taskwindow that lets you enter the real and imaginary
parts of a Gaussian integer and then prints out its
factorization into irreducible Gaussian integers. The
program does not use the scheme described above, which was
given simply to illustrate a use of metatables.
do
local fmt1 = [[
%s factorizes as the product
of the irreducibles:
]]
local fmt2 = "\ntimes the unit %s.\n"
local prettyformat = \(x,y)
if y == 0 then => tostring(x) end
if y == 1 then
if x == 0 then => "i"
else => tostring(x).." + i" end
end -- if
if y == -1 then
if x == 0 then => "-i"
else => tostring(x).." - i" end
end -- if
if x == 0 then
=> tostring(y).."i" end
if y > 0 then
=> tostring(x).." +
"..tostring(y).."i"
else
=> tostring(x).." -
"..tostring(-y).."i"
end
end
local norm = \(x,y) => x*x + y*y end
local smallestprime = \(n)
if n%2 == 0 then => 2 end
local p,k = 1
repeat
p = p+2
k = n%p
until p*p > n or k == 0
if k == 0 then => p
else => n
end -- if
end
local divide = \(x,y,a,b)
local d = norm(a,b)
=> (x*a+y*b)/d, (y*a-x*b)/d
end
local irredfact = \(x,y,p)
local a,b = 1,1
while norm(a,b) < p do
a = a + 1
if norm(a,b) > p then
a,b = 1,b + 1
end -- if
end -- while
if (x*a+y*b)%p == 0 and
(y*a-x*b)%p == 0 then
=> a,b
else
=> b,a
end -- if
end
print [[
Enter a Gaussian integer as two integers
(real and imaginary parts)]]
print "separated by a space."
local x,y = io.read("*n","*n")
io.write(fmt1:format(prettyformat(x,y)))
local a,b -- complex irreducible factor
local n = norm(x,y)
while n > 1 do
local p = smallestprime(n)
if p == 2 then
print (prettyformat(1,1))
x,y = divide(x,y,1,1)
elseif p%4 == 3 then
print (prettyformat(p,0))
x,y = divide(x,y,p,0)
else a,b = irredfact(x,y,p)
print (prettyformat(a,b))
x,y = divide(x,y,a,b)
end -- if
n = norm(x,y)
end -- while
io.write(fmt2:format(prettyformat(x,y)))
end -- do
event is very interesting. If we set
the value of
all the keys it does not itself have.
In this way we can program any variant of the notion of
that the ideas of object oriented programming
may suggest to us. The colon notation for strings is a consequence
of the fact that every string has for its metatable
A similar device is used for file handles and for doubles.
However, only tables can have their metatables set by the user
from within Lua.