I'm building a simple game and I've been following the PIL book. Here is the scenario I am basing my game off of:
http://www.lua.org/pil/16.1.html
I'm struggling because there is only one module in the book and I'm trying to get 8 modules working together.
Here's a small part of my game: I have a Game module, a Board module and a Input/Output module for now.
I thought I understood when to use colon and when to use period, but I'm not understanding why, in the PIL example, the author is passing in "o" to the "new" method and why there is a colon on that method?
My Game module is supposed to be my highest level module. In it, I would think I would new up the board and input/output modules and get those working together. But what do those "new" (meaning initialize) methods look like for the board and input/output modules?
Here some code I've been working with (simplified):
Game = {}
function Game:new(o)
o = {} or o
setmetatable(o, self)
self.__index = self
-- need board and input_output instances below
o.board = Board:new(o)
o.input_output = Input_Output:new(o)
return o
end
return Game
----------------------------------------------------
Board = {}
function Board:new(o)
o = o or {}
-- need layout attribute here
o.layout = { create_layout() }
setmetatable(o, self)
self.__index = self
return o
end
return Board
---------------------------------------------------
Input_Output = {}
function Input_Output:new(o)
o = o or {}
-- need read and write attributes here
o.read = stdin
o.write = stdout
setmetatable(o, self)
self.__index = self
return o
end
return Input_Output
In an OOP language like Ruby, Game would hold instances of my Board and Input_Output classes. Then if I drilled down to game.board, I could see the public attributes and public methods on board.
However, when I am newing up these 2 "classes" in game, something weird is going on. My self and o variables are not what I would expect them to be (I'm using lua_inspect). I seem to maybe be overwriting data in the o variable with each new instance of a module?
I'm so lost and I think it's because of the "new" method. I'm just not getting it.
Can anyone explain? My questions mainly are - what's with the "o" in the example and why is there a colon on the "new" method?
Actually there's no "official" classes in Lua, so you can implement them any way you want. In this particular implementation o
is the new instance, possibly with some pre-defined parameters. It inherits all members of parent, be they values or methods - functions - that's all the same in Lua. If you do not supply an o
in this call at all, an empty table will be created for you.
:
in function definition is just a syntactic sugar for function Game.new(self, o)
- that is, it adds a very first parameter called self
.
You should call this function like local my_game = Game:new()
. After that, my_game
will be a table that have my_game.board
and my_game.input_output
members.
Your current question is not exactly clear on what do you see and how it is different from what you expect. If you provide more details, I can add more details to answer too.
I trying to explain this. It will also help me to understand this deeper.
So, just look at the example in http://www.lua.org/pil/16.1.html.
Account = {}
function Account:new (o)
o = o or {} -- create object if user does not provide one
setmetatable(o, self)
self.__index = self
return o
end
Understand Function in Lua
function foo (x) return 2*x end
is just an instance of what we call syntactic sugar; in other words, it is just a pretty way to write
foo = function (x) return 2*x end
And you know that :
is only a syntactic facility for .
.
function Account:new (o)
is the same as
function Account.new ( Account, o )
So above all, we know
function Account:new (o)
is the same as
Account.new = function( Account, o )
How do we find something in a Lua Table
a = Account.new
The finding process below:
Find if there is a 'new' key in `Account`? --Yes-- Return `Account.new`
|
No
|
Check if `Account` has a metatable? --No-- Return `nil`
|
Yes
|
Check if there is a 'new' key in the `__index` field of `Account`'s metatable --No-- Return `nil`
|
Yes
|
Assume `metaAccount` is the metatable of Account
Return `metaAccount.__index.new`
What does Account:new
do
o = o or {} -- just create a new table if the input o is nil
setmetatable(o, self) -- self is Account because of `:`, and set o's metatable to Account
self.__index = self -- the same as Account.__index = Account, this is set the `__index` field of Account, which is o's metatable
return o --return o, a table which has a metatable `Account`, and `Account` has a `__index` field is also `Account`
How it works
We define another function
function Account:print() --the same as Account.print = function( self )
print("Class Account.")
end
a = Account:new() --a is a table which has a metatable `Account`, and `Account` has a `__index` field is also `Account`
a:print() --find a.print in a's metatable `Account` as a function, and run it
-->Class Account.
You shall clear now...
So to focus on "what's with the 'o' in the example and why is there a colon on the "new" method?":
So Game is the class: it is a table with functions. That's the basic notion of class in Lua. So what is an instance of Game? It is a table whose metatable is its class's table namely Game.
But in Lua a function in a table can't know what table it is in except if it is given this info as call parameter. Lua makes this easy by automatically giving reference to containing table as first parameter to function when you call it with the colon instead of dot. This first param has name "self". So in the "new" function, calling it with colon provides the table that new is defined in as self param, ie the class Game.
So you can see that 'o' is the instance you are creatiing, and you call new with colon because otherwise you would have to give it the class table which would then appear twice in your statement ie colon provides nicer syntax.