The object system described only works if a class contains values; it falls apart when the class contains a reference (like a table). This happens because tables are passed by reference not value. When the __index meta function returns a table contained in a class, there is no new copy of that table, just a reference that is shared among every instance of the class. The following code demonstrates this:
Character = {
alive = true
}
Character.position = {
x = 10, y = 20, z = 30
}
Character.new = function(self, object)
object = object or {}
setmetatable(object, self)
self.__index = self
return object
end
player1 = Character:new()
player2 = Character:new()
player1.position.x = 0
player2.position.y = 10
print ("Player 1, position: ("
.. player1.position.x .. ", " .. player1.position.y
.. ", " .. player1.position.z .. ")")
print ("Player 2, position: ("
.. player2.position.x .. ", " .. player2.position.y
.. ", " .. player2.position.z .. ")")
if player1.position == player2.positon then
print ("Player 1 and 2 have the same position reference");
else
print ("Player 1 and 2 have unique positon tables");
end
print ("Table id:")
print ("Player 1: " .. tostring(player1.position))
print ("Player 2 :" .. tostring(player2.position))
This can be fixed by making sure that each instance of the Character class has a unique copy of the position table. The best place to add this table is in the constructor, before the __index meta method is assigned. That is, the new function must assign per instance member tables before setting the meta table of an object. This code fixes the problem with the previous code sample:
Character.new = function(self, object)
object = object or {}
-- Assign per instance variables after the object is valid
-- but before setting the meta table! Copy all members of
-- the new table by value!
object.position = {}
object.position.x = Character.position.x
object.position.y = Character.position.y
object.position.z = Character.position.z
setmetatable(object, self)
self.__index = self
return object
end