Confused about Lua metatables on page 108 of Programming in Lua

412 Views Asked by At

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?

1

There are 1 best solutions below

5
On BEST ANSWER

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 changed for e in pairs(set) to for e in pairs(Set) and so it always shows the contents of Set, not the contents of the given set.