I'm studying Lua, using the book Programming in Lua, first edition. I'm having trouble understanding metatables.
This is the code and explanations that appear on page 108:
Set = {} function Set.new (t) local set = {} for _, l in ipairs(t) do set[l] = true end return set end function Set.union (a,b) local res = Set.new{} for k in pairs(a) do res[k] = true end for k in pairs(b) do res[k] = true end return res end function Set.intersection (a,b) local res = Set.new{} for k in pairs(a) do res[k] = b[k] end return res end
To help checking our examples, we also define a function to print sets:
function Set.tostring (set) local s = "{" local sep = "" for e in pairs(set) do s = s .. sep .. e sep = ", " end return s .. "}" end function Set.print (s) print(Set.tostring(s)) end
Now, we want to make the addition operator (
+
) compute the union of two sets. For that, we will arrange that all tables representing sets share a metatable and this metatable will define how they react to the addition operator. Our first step is to create a regular table that we will use as the metatable for sets. To avoid polluting our namespace, we will store it in the Set table:Set.mt = {} -- metatable for sets
The next step is to modify the Set.new function, which creates sets. The new version has only one extra line, which sets mt as the metatable for the tables that it creates:
function Set.new (t) -- 2nd version local set = {} setmetatable(set, Set.mt) for _, l in ipairs(t) do set[l] = true end return set end
After that, every set we create with Set.new will have that same table as its metatable:
s1 = Set.new{10, 20, 30, 50} s2 = Set.new{30, 1} print(getmetatable(s1)) --> table: 00672B60 print(getmetatable(s2)) --> table: 00672B60
Finally, we add to the metatable the so-called metamethod, a field __add that describes how to perform the union:
Set.mt.__add = Set.union
Whenever Lua tries to add two sets, it will call this function, with the two operands as arguments.
With the metamethod in place, we can use the addition operator to do set unions:
s3 = s1 + s2 Set.print(s3) --> {1, 10, 20, 30, 50}
When I tried to run it, I got the result: { union, mt, intersection, tostring, new, print}
instead of the numbers in s3
. Seems I've printed the contents of the metatables instead. Can someone explain what's happening here? The book describes version 5.0 and I'm using Lua 5.1. Could that be causing this?
There is a bug in the code you ran, not in the code you've posted in the question:
In
Set.tostring
, line 28, you changedfor e in pairs(set)
tofor e in pairs(Set)
and so it always shows the contents ofSet
, not the contents of the given set.