Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

What does this line of code mean? Metatables
Started by vonncc123 Mar 31 2019 10:14 PM

- - - - -
7 replies to this topic
metatable
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

vonncc123

[GLOBAL: userInfoPane.html]
vonncc123
  • Contributor

  • 236 posts
  • Corona SDK

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 :)

 

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.



[TOPIC: post.html]
#2

thomas6

[GLOBAL: userInfoPane.html]
thomas6
  • Contributor

  • 975 posts
  • Corona SDK

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.



[TOPIC: post.html]
#3

vonncc123

[GLOBAL: userInfoPane.html]
vonncc123
  • Contributor

  • 236 posts
  • Corona SDK

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. :) 



[TOPIC: post.html]
#4

thomas6

[GLOBAL: userInfoPane.html]
thomas6
  • Contributor

  • 975 posts
  • Corona SDK

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.



[TOPIC: post.html]
#5

vonncc123

[GLOBAL: userInfoPane.html]
vonncc123
  • Contributor

  • 236 posts
  • Corona SDK

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?



[TOPIC: post.html]
#6

thomas6

[GLOBAL: userInfoPane.html]
thomas6
  • Contributor

  • 975 posts
  • Corona SDK

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!



[TOPIC: post.html]
#7

vonncc123

[GLOBAL: userInfoPane.html]
vonncc123
  • Contributor

  • 236 posts
  • Corona SDK

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



[TOPIC: post.html]
#8

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,337 posts
  • Enterprise

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




[topic_controls]
[/topic_controls]

Also tagged with one or more of these keywords: metatable