What are the differences between the variables (o.x and self.y) later on?
You have two tables here, object
and o
.
Inside of object:new
, self
refers to the table object
. So self.y
is a field in the table object
.
o
is the new table you create in each call to object:new
. o.x
is a field in the table o
.
That o
table only has one entry: o["x"]
, so when you iterate over the entries in the table (as print_r
does), that's all you're going to see.
So why does o.y
give you a value? Because you set the table object
as o
's metatable and that metatable has it's __index
field set, so when an index attempt fails on o
, Lua will try again via o
's metatable (if it has __index set).
A little code will probably make this clearer:
o = { x = 33 }
print(o.x, o.y) --> 33 nil
-- let's give o a metatable
mt = { y = 20 }
setmetatable(o, mt)
-- we've given o a metatable, but that metatable doesn't have an __index member set
print(o.y) --> nil
-- metatable `handlers` are normally functions that handle events
-- here we create a handler for indexing a table if the key doesn't exist in the table:
mt.__index = function(t,k)
print("An attempt was made to index table", t, "with the key", k)
return 5150
end
-- we've given o's metatable a handler for indexing which always returns 5150
print(o.x) --> 33
print(o.y) --> 5150
print(o.z) --> 5150
print(o.donut) --> 5150
-- note that Lua has a "rawget" function, which bypasses the metatable mechanics
print(rawget(o,'x')) --> 33, we get a value, because o actually contains "x"
print(rawget(o,'y')) --> nil, back to nil, because the metatable is being ignored
-- the __index metatable handler is special. Instead of providing a function
-- to handle missing key events, you can give it a table. If an index attempt fails,
-- it will try again in the __index table
mt.__index = mt -- we could have used a third table here, but mt has the y entry we want
-- we've changed the metatable handler, so now we'll get 777
print(o.y) --> 777
-- changes to the metatable are reflected in any object using it as metatable
mt.__index.y = 999
print(o.y) --> 999
-- now we give `o` it's OWN "y" entry, so the metatable handler will no longer be invoked
o.y = 2112
print(o.y) --> 2112
print(rawget(o, 'y')) --> o really owns this "y" entry
print(mt.__index.y) --> 999, the metatable was untouched by our write to o.y