What does this line of code mean? Metatables

Good day,

What’s the meaning of this code?

local new\_class = {} local class\_mt = { \_\_index = new\_class }
  1. create a new_class with a value of an empty array/table.

  2. class_mt = ???, is __index equal to an empty array/table? Please enlighten me thanks in advance :slight_smile:

and what happens when I use class_mt as a parameter in setmetatable? All I know is when it sees an __Index method, It triggers when the used adds a new index on an array/table.

Hi Vonncc123,

Can I try and answer besides the question?

The meaning of the code, as you surely know, is to set metatables of one objects to the metatable of another.

Personally, I always found this code to be very confusing. I could never remember it and so always had to copy it from a template file. Even today I can’t remember exactly what the syntax or order is.

For the vast majority of use cases (i.e. just writing modules for your game characters and enemies etc…) I would suggest that you leave metatables alone and go for the vastly more understandable modular pseudo-object oriented programming.

That means, for an enemy you create something like this:

-------------------- -- enemyClass.lua -- -------------------- local enemyClass = {} enemyClass.new = function(parent) -- parent is optional but handy, read below local self = {} self.type = "enemy" self.parent = parent -- passing the parent to child objects make it supereasy for them to talk to their "parents" -- after this you can add all the displayObjects you want self.mainGroup = display.newGroup() self.rectangle = display.newRect(self.mainGroup, 200,200,100,100) -- and then you can write all the functions you want self.changeColor = function() local randomRed = math.random(255)/255 local randomGreen = math.random(255)/255 local randomBlue = math.random(255)/255 self.rectangle:setFillColor(randomRed, randomGreen, randomBlue) end -- self.changeColor() self.frameLoop = function(event) self.rectangle.rotation = self.rectangle.rotation+1 end -- self.frameLoop() -- and in the end you can add all timers or evenListener you want to Runtime:addEventListener("enterFrame", self.frameLoop) self.changeColorTimer = timer.performWithDelay(1000, self.changeColor, 0) -- and then lastly it's best to write a "kill" function that you can call from the parent, to clean up the object self.kill = function() -- 1 first clean up the timers, transition and eventListeners Runtime:removeEventListener("enterFrame", self.frameLoop) timer.cancel(self.changeColorTimer) -- 2 then clean up all child objects, if there are eny -- in this case there are none -- 3 then clean up all the displayObjects -- 4 if needed, set any non-local variables to nil -- typically if you code well, you won't have any global variables so this step if unnecessary end -- self.kill() return self end -- enemyClass.new() return enemyClass

Then what you do, is in a parent module, you require the “enemyClass.lua”, and then create a new object like this:

parentObject.myEnemy = enemyClass.new(parentObject) – where self is the parent object

In reality, if you code everything like this, the parentObject will also refer to itself by the term “self”, so it would probably look like this:

self.myEnemy = enemyClass.new(self)

Or even more realistic, you will have multiple enemies in a table, so creating will look like this, called from the parent:

self.enemyList[1] = enemyClass.new(self)

I hope this make some sense to you, although I can image if this is new stuff, it’s confusing at first. But I can tell you that for me personally this is the best, fastest, clearest and easiest way to do things.

If you can’t manage to make this work, let me know and I’ll write you some more demo code.

Thanks for the tip, Fortunately I’ve already done the same way as you do, what piqued my interest is inheriting methods from other classes. That’s why I got curious with metatables. So that when I get to use other lnaguages ie Java, C#, I can implement the same methodologies in inheritance. :) 

Hi Vonn,

The method I showed does allow inheritance as well: you can easily create a subclass and add or detail functions (or properties).

I have to say: OOP in Lua does not work the same way as Java and C#, so I don’t think to knowledge would transfer over so directly. Metatables are very much a Lua thing, and don’t exist in other common languages.

Thanks, How do you do inheritance, in your style? What I imagine is something like this

 

local myObjject = {} myObject.mystyle = 123 myObject = --Inheritance happens here

the problem here is what If I wanted to combine my object and inherit something with it, it will overwrite the myObject and remove mystyle, how can I maintain mystyle while inheriting other classes?

Let’s say you have a broad “enemyClass”, and you want to create a “dragonClass” as an inherited object.

Using my code above for the enemyClass you would create the dragonClass as follows:

local enemyClass = require("enemyClass") -- -- local dragonClass = {} dragonClass.new = function() local self = enemyClass.new() -- then add the extra code for the inherited class self.dragonImage = display.newRect(0,0,200,200) return self end -- dragonClass.new() return dragonClass

This would create a dragonClass based on the enemyClass!

okay pretty much the same I make it :). I though there would be other way :slight_smile: Thank you :slight_smile:

in essence a metatable says “if reference not found in base then resolve in the metatable” (re __index).

you can do all sorts of things with that mechanism, including OOP-style inheritence.

it’s worth reading all of PIL ch16:  https://www.lua.org/pil/16.html

but there are other approaches (prototypes, closures, factories, …) fe:  http://lua-users.org/wiki/ObjectOrientedProgramming

Hi Vonncc123,

Can I try and answer besides the question?

The meaning of the code, as you surely know, is to set metatables of one objects to the metatable of another.

Personally, I always found this code to be very confusing. I could never remember it and so always had to copy it from a template file. Even today I can’t remember exactly what the syntax or order is.

For the vast majority of use cases (i.e. just writing modules for your game characters and enemies etc…) I would suggest that you leave metatables alone and go for the vastly more understandable modular pseudo-object oriented programming.

That means, for an enemy you create something like this:

-------------------- -- enemyClass.lua -- -------------------- local enemyClass = {} enemyClass.new = function(parent) -- parent is optional but handy, read below local self = {} self.type = "enemy" self.parent = parent -- passing the parent to child objects make it supereasy for them to talk to their "parents" -- after this you can add all the displayObjects you want self.mainGroup = display.newGroup() self.rectangle = display.newRect(self.mainGroup, 200,200,100,100) -- and then you can write all the functions you want self.changeColor = function() local randomRed = math.random(255)/255 local randomGreen = math.random(255)/255 local randomBlue = math.random(255)/255 self.rectangle:setFillColor(randomRed, randomGreen, randomBlue) end -- self.changeColor() self.frameLoop = function(event) self.rectangle.rotation = self.rectangle.rotation+1 end -- self.frameLoop() -- and in the end you can add all timers or evenListener you want to Runtime:addEventListener("enterFrame", self.frameLoop) self.changeColorTimer = timer.performWithDelay(1000, self.changeColor, 0) -- and then lastly it's best to write a "kill" function that you can call from the parent, to clean up the object self.kill = function() -- 1 first clean up the timers, transition and eventListeners Runtime:removeEventListener("enterFrame", self.frameLoop) timer.cancel(self.changeColorTimer) -- 2 then clean up all child objects, if there are eny -- in this case there are none -- 3 then clean up all the displayObjects -- 4 if needed, set any non-local variables to nil -- typically if you code well, you won't have any global variables so this step if unnecessary end -- self.kill() return self end -- enemyClass.new() return enemyClass

Then what you do, is in a parent module, you require the “enemyClass.lua”, and then create a new object like this:

parentObject.myEnemy = enemyClass.new(parentObject) – where self is the parent object

In reality, if you code everything like this, the parentObject will also refer to itself by the term “self”, so it would probably look like this:

self.myEnemy = enemyClass.new(self)

Or even more realistic, you will have multiple enemies in a table, so creating will look like this, called from the parent:

self.enemyList[1] = enemyClass.new(self)

I hope this make some sense to you, although I can image if this is new stuff, it’s confusing at first. But I can tell you that for me personally this is the best, fastest, clearest and easiest way to do things.

If you can’t manage to make this work, let me know and I’ll write you some more demo code.

Thanks for the tip, Fortunately I’ve already done the same way as you do, what piqued my interest is inheriting methods from other classes. That’s why I got curious with metatables. So that when I get to use other lnaguages ie Java, C#, I can implement the same methodologies in inheritance. :) 

Hi Vonn,

The method I showed does allow inheritance as well: you can easily create a subclass and add or detail functions (or properties).

I have to say: OOP in Lua does not work the same way as Java and C#, so I don’t think to knowledge would transfer over so directly. Metatables are very much a Lua thing, and don’t exist in other common languages.

Thanks, How do you do inheritance, in your style? What I imagine is something like this

 

local myObjject = {} myObject.mystyle = 123 myObject = --Inheritance happens here

the problem here is what If I wanted to combine my object and inherit something with it, it will overwrite the myObject and remove mystyle, how can I maintain mystyle while inheriting other classes?

Let’s say you have a broad “enemyClass”, and you want to create a “dragonClass” as an inherited object.

Using my code above for the enemyClass you would create the dragonClass as follows:

local enemyClass = require("enemyClass") -- -- local dragonClass = {} dragonClass.new = function() local self = enemyClass.new() -- then add the extra code for the inherited class self.dragonImage = display.newRect(0,0,200,200) return self end -- dragonClass.new() return dragonClass

This would create a dragonClass based on the enemyClass!

okay pretty much the same I make it :). I though there would be other way :slight_smile: Thank you :slight_smile:

in essence a metatable says “if reference not found in base then resolve in the metatable” (re __index).

you can do all sorts of things with that mechanism, including OOP-style inheritence.

it’s worth reading all of PIL ch16:  https://www.lua.org/pil/16.html

but there are other approaches (prototypes, closures, factories, …) fe:  http://lua-users.org/wiki/ObjectOrientedProgramming