middleclass & extras: middleclass 3.0 is out!
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
middleclass & extras: middleclass 3.0 is out!
Hi everyone,
Version 3.0 is out. Details on this post: viewtopic.php?f=5&t=1053
Download: https://github.com/kikito/middleclass
Version 3.0 is out. Details on this post: viewtopic.php?f=5&t=1053
Download: https://github.com/kikito/middleclass
Last edited by kikito on Wed Sep 18, 2013 10:21 pm, edited 5 times in total.
When I write def I mean function.
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: MiddleClass & MindState: Object Orientation for LUA
I've started the MindState documentation on the wiki. Since this post can be used for asking questions about both, I've changed its title.
The example there is specially dedicated to one of the LÖVE developers. I'll try to add more examples later on.
The example there is specially dedicated to one of the LÖVE developers. I'll try to add more examples later on.
When I write def I mean function.
Re: MiddleClass & MindState: Object Orientation for LUA
was looking trough MC and have one question - is it possible to have private fields in classes? Say not necessary methods, but variables? Maybe there is some universal solution or recommendation for private use with MC?
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: MiddleClass & MindState: Object Orientation for LUA
It is quite funny that you mention it.
That was the next thing I was to include on the MiddleClass wiki.
...
Done! Please give it another look and let me know what you think.
That was the next thing I was to include on the MiddleClass wiki.
...
Done! Please give it another look and let me know what you think.
When I write def I mean function.
Re: MiddleClass & MindState: Object Orientation for LUA
It's good description, I like it As of use cases you presented there I think it's more than enough for normal uses of private scope for class
Btw. I was thinking about what other examples could be cool - you can also give example of Singleton implementation
Btw. I was thinking about what other examples could be cool - you can also give example of Singleton implementation
Re: MiddleClass & MindState: Object Orientation for LUA
One small question... in wiki you say that :new part is implicit, i.e. there is __call for classes, right? But when I try:
it gives me that I attempt to call table. What am I missing here?
Code: Select all
> require 'MiddleClass'
> Game = class('Game')
> game1 = Game:new()
> game2 = Game()
stdin:1: attempt to call global 'Game' (a table value)
stack traceback:
stdin:1: in main chunk
[C]: ?
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: MiddleClass & MindState: Object Orientation for LUA
Hi there!
No that was a bug. Thanks for spotting it.
I've fixed MiddleClass, implicit instantiation should be working again.
No that was a bug. Thanks for spotting it.
I've fixed MiddleClass, implicit instantiation should be working again.
When I write def I mean function.
Re: MiddleClass & MindState: Object Orientation for LUA
yup, works now
Re: MiddleClass & MindState: Object Orientation for LUA
I just wonder, what do you think about this Singleton implementation?
I was thinking about it, because in your MindState example you showed the Game state management - in the example there is Game class and bunch of states classes - the issue in example is though as far as I understand it (you write game:gotoState('OptionsMenu'), each state would have to know which instance of Game class it's running with - natural way to walk around this is by using singleton pattern - but is there any better way than above to build singleton using MC?
Code: Select all
Game = class('Game')
local _GameInstance = nil
function Game:instance()
return _GameInstance or Game:new()
end
function Game:initialize()
assert(not _GameInstance, "Game is a singleton")
_GameInstance=self
end
getmetatable(Game).__call = Game.instance
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: MiddleClass & MindState: Object Orientation for LUA
Hmm I think you have made me spot another weakness on middleclass.
The _call parameter is calling Object.new, but it should really be invoking the class:new. In other words when you do this:
It is really doing this:
It should be doing this instead:
This way, if you override Game.new, the Game() call would just use that new implementation - you would not have to repeat the overriding on _call.
I'll try to make that change this evening.
Now, to your question: singletons. Here's my view of them: their implementation requirements are very dependent on their target users.
On your example, you will be the only one using your Game object, so in reality, you would be just fine without singletons; you can just create one single global variable and trust that you will not create another one later on. Small improvement just for the laughts: making the whole Game class private, and a game instance public.
Now you can't create other games. Well, not directly: You can still do game.class:new() ... so you might probably want to override new() method to throw an error after the game variable is created (after the fix I'll do today you will not have to mess around with _call).
But again, if you are going to be the only user of your class, those security measures aren't really necessary.
But what about Singletons in general? What would be the best way to create them with MiddleClass?
Well, consider the following: Every time you create a new singleton you would have to do the same things: create the class, then create a single private instance variable, then override create a getter for that private instance, and then override the new function so it throws an error.
Well, I'm a very big fan of code reuse. This repetitiveness suggests that it should be probably managed with code.
Mixins are a great tool for this job. Consider the following Singleton Mixin:
The 'included()' method is executed when the Mixin is included in a class (by the way I need to add the '...' parameters to middleClass). This is saying: when the mixin is included, generate a private variable for that class called 'instance' invoking class:new.
The other two functions are just adding a new function to class (getInstance) that returns the private variable and overriding new() so it throws an error.
Here's how you would use it with Game:
Finally, a couple comments about nomenclature - These are just recommendations, feel free to not adhere to them.
The _call parameter is calling Object.new, but it should really be invoking the class:new. In other words when you do this:
Code: Select all
game = Game()
Code: Select all
game = Object.new(Game)
Code: Select all
game = Game:new()
I'll try to make that change this evening.
Now, to your question: singletons. Here's my view of them: their implementation requirements are very dependent on their target users.
On your example, you will be the only one using your Game object, so in reality, you would be just fine without singletons; you can just create one single global variable and trust that you will not create another one later on. Small improvement just for the laughts: making the whole Game class private, and a game instance public.
Code: Select all
-- File 'Game.lua'
local Game = class('Game', StatefulObject) -- notice the local here
function Game:initialize()
...
end
...-- states, etc
game = Game:new()
Code: Select all
game = Game:new()
function Game:new()
error('Explicit creation of games is forbidden. Use the game global variable instead')
end
But what about Singletons in general? What would be the best way to create them with MiddleClass?
Well, consider the following: Every time you create a new singleton you would have to do the same things: create the class, then create a single private instance variable, then override create a getter for that private instance, and then override the new function so it throws an error.
Well, I'm a very big fan of code reuse. This repetitiveness suggests that it should be probably managed with code.
Mixins are a great tool for this job. Consider the following Singleton Mixin:
Code: Select all
-- File 'Singleton.lua'
local private = {}
Singleton = {
included=function(class, ...)
private[class] = { instance = class:new(...) }
end
}
function Singleton:getInstance()
return private[self].instance
end
function Singleton:new()
error("Object creation is forbidden on singletons")
end
The other two functions are just adding a new function to class (getInstance) that returns the private variable and overriding new() so it throws an error.
Here's how you would use it with Game:
Code: Select all
-- File 'Game.lua'
require('singleton.lua')
Game = class('Game', StatefulObject)
function Game:initialize()
...
end
...-- states, etc
-- It is important that this is done at the end, or at least after the Game:initialize() function is defined. Otherwise it will not work
Game:includes(Singleton, ...) -- the ... means 'parameters for creating the game instance, if any'
- I think methods should be "verbal" when possible. I would have called the "instance" method "getInstance"
- Uppercases are better left for classes and mixins. Attributes and methods, lowercased. So I would have called the instance gameInstance instead of GameInstance.
When I write def I mean function.
Who is online
Users browsing this forum: No registered users and 4 guests