Page 1 of 3
Create a class without external libraries
Posted: Thu Feb 11, 2016 9:59 pm
by Kibita
Hello!
I wonder how you guys make your own class in Lua without using external libraries like middleClass. I'm a little stuck in this part because I don't wan't to make something wrong that could imply a bad coding. So, what's is the most formal way to make classes in lua?
Thank you!
Re: Create a class without external libraries
Posted: Thu Feb 11, 2016 10:10 pm
by bobbyjones
There isn't. You can do it whatever way you like. Some use closures and some use metatables. It depends on what you want or need.
With closures -
http://theindiestone.com/forums/index.p ... etatables/
With metatables -
http://lua-users.org/wiki/ObjectOrientationTutorial
Re: Create a class without external libraries
Posted: Thu Feb 11, 2016 10:43 pm
by Kibita
So it is right what I am doing?
Code: Select all
local Game = {}
Game.__index = Game
function Game:new(meter, gravity)
setmetatable({}, Game)
-- Set physics parameters
love.physics.setMeter(meter)
self.world = love.physics.newWorld(0, gravity*meter, true)
-- Load background
self.background = love.graphics.newImage("img/background.png")
-- Create the Balls
self.balls = {}
self.balls.left = Ball:new(self.world, 75, 5, 150) -- Insert the left ball
self.balls.right = Ball:new(self.world, 75, 570, 150) -- Insert the right ball
-- Create the player
self.player = nil
-- Attatch the balls to the player
return self
end
...
Re: Create a class without external libraries
Posted: Fri Feb 12, 2016 1:16 am
by bobbyjones
Actually if you are just starting out I recommend the closure approach it's easier to understand. But anyways if your code works and does what your expect it to then yes it is right. If it doesn't then we'll you are doing it wrong. If you tested the code properly you would notice an error. Instead of returning self return the setmetatable({},Game).
Re: Create a class without external libraries
Posted: Fri Feb 12, 2016 8:47 am
by Roland_Yonaba
I would just suggest to go along with PiL's approach,
chapter 16.
Also, even though I do not consider this to be anywhere formal,
here is the bare-bones light class implementation I am mostly using when I need one.
Re: Create a class without external libraries
Posted: Fri Feb 12, 2016 12:36 pm
by airstruck
Code: Select all
Game.__index = Game
...
setmetatable({}, Game)
That pattern has always felt wrong to me. I'm not sure how it got so popular. The __index property does not really belong in your Game class, and none of Game's properties really belong in the metatable. It works alright, it just seems messy and semantically non-obvious.
I'd probably use a dedicated metatable instead:
Code: Select all
local meta = { __index = Game }
...
setmetatable({}, meta)
Or just create them on the fly if you don't care about a few extra tables.
Code: Select all
setmetatable({}, { __index = Game })
Also, in your Game:new method you create a new instance with setmetatable({}, Game), but you don't assign the result to anything, and then you use self (which refers to the Game class) as if it were the instance you created. This won't work the way you probably intend.
Once you fix that, there's another problem with having the "instantiator" and constructor both in one function (Game:new). If you want to use inheritance, you have no way of applying the parent constructor to an instance of a subclass, because there are no dedicated constructors, only the "instantiator."
Here is the
base class I use when I need classical OOP, if you're interested. When I don't feel like including that, I sometimes use a snippet like this instead:
Code: Select all
local Foo = setmetatable({}, {
__call = function (self, ...)
local object = setmetatable({}, { __index = self })
return object, self.constructor(object, ...)
end
})
Re: Create a class without external libraries
Posted: Fri Feb 12, 2016 3:33 pm
by rmcode
I prefer the closure based approach:
Code: Select all
local ClassName = {};
function ClassName.new()
local self = {};
local baz = 'Foo is Löve, All is Löve' -- Private attribute
self.bazooka = true -- Public attribute
-- Private function
local function bar()
-- Do stuff
end
-- Public function
function self:foo()
-- Do stuff
end
return self;
end
return ClassName;
It makes for clean and readable code and makes it easy to use inheritance.
Re: Create a class without external libraries
Posted: Fri Feb 12, 2016 4:25 pm
by airstruck
That's nice and readable, no metatables, allows private members.
Each object has its own copy of all methods and private functions, which could be a performance consideration. When using metatables, all instances of a class share the same methods. You could get that without metatables by doing this kind of thing:
Code: Select all
-- classname.lua
-- Private function
local function bar (self)
-- Do stuff
end
-- Public function
local function foo (self)
-- Do stuff
end
-- Constructor
return function (x, y)
return {
-- Constructor args
x = x, y = y,
-- Default properties
bazooka = true,
-- Public methods
foo = foo,
}
end
It doesn't look as nice, but you get reusable methods. You'll still have private functions, and it will be easy to expose them as public functions by adding them to the returned object. You won't have private instance variables, but you can have "static" privates.
If your module returns a
table of constructors for similar things, this will give you nice mixin-like reuse of methods and you won't need inheritance.
Re: Create a class without external libraries
Posted: Fri Feb 12, 2016 10:28 pm
by Kibita
bobbyjones wrote:Actually if you are just starting out I recommend the closure approach it's easier to understand. But anyways if your code works and does what your expect it to then yes it is right. If it doesn't then we'll you are doing it wrong. If you tested the code properly you would notice an error. Instead of returning self return the setmetatable({},Game).
The unique trouble I'm facing right now is when I create two objects from the same class:
Code: Select all
-- Create the Balls
self.balls = {}
self.balls.left = Ball:new(self.world, ballRadius, 0, gameHeight / 2) -- Insert the left ball
self.balls.right = Ball:new(self.world, ballRadius, gameWidht - ballRadius, gameHeight / 2) -- Insert the right ball
It just show one (actually I think both are created, but they share the same information like position and size, so one of the balls are covering the other, making it not visible)
Re: Create a class without external libraries
Posted: Sat Feb 13, 2016 12:44 am
by bobbyjones
Yup its because you returned self and not the setmetatable({},Game)