## middleclass & extras: middleclass 3.0 is out!

kikito
Inner party member
Posts: 3047
Joined: Sat Oct 03, 2009 5:22 pm
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

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: 3047
Joined: Sat Oct 03, 2009 5:22 pm
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.
When I write def I mean function.

giniu
Party member
Posts: 221
Joined: Mon Nov 30, 2009 4:44 pm

### 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: 3047
Joined: Sat Oct 03, 2009 5:22 pm
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.
When I write def I mean function.

giniu
Party member
Posts: 221
Joined: Mon Nov 30, 2009 4:44 pm

### 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

giniu
Party member
Posts: 221
Joined: Mon Nov 30, 2009 4:44 pm

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

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]: ?

it gives me that I attempt to call table. What am I missing here?

kikito
Inner party member
Posts: 3047
Joined: Sat Oct 03, 2009 5:22 pm
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.
When I write def I mean function.

giniu
Party member
Posts: 221
Joined: Mon Nov 30, 2009 4:44 pm

### Re: MiddleClass & MindState: Object Orientation for LUA

yup, works now

giniu
Party member
Posts: 221
Joined: Mon Nov 30, 2009 4:44 pm

### Re: MiddleClass & MindState: Object Orientation for LUA

Code: Select all

Game = class('Game')local _GameInstance = nilfunction Game:instance()  return _GameInstance or Game:new()endfunction Game:initialize()  assert(not _GameInstance, "Game is a singleton")  _GameInstance=selfendgetmetatable(Game).__call = Game.instance
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?

kikito
Inner party member
Posts: 3047
Joined: Sat Oct 03, 2009 5:22 pm
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:

Code: Select all

 game = Game()

It is really doing this:

Code: Select all

 game = Object.new(Game)

It should be doing this instead:

Code: Select all

 game = Game:new()

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.

Code: Select all

-- File 'Game.lua'local Game = class('Game', StatefulObject) -- notice the local herefunction Game:initialize()...end...-- states, etcgame = Game:new()

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

Code: Select all

game = Game:new()function Game:new()  error('Explicit creation of games is forbidden. Use the game global variable instead')end

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:

Code: Select all

-- File 'Singleton.lua'local private = {}Singleton = {  included=function(class, ...)    private[class] = { instance = class:new(...) }  end}function Singleton:getInstance()  return private[self].instanceendfunction Singleton:new()  error("Object creation is forbidden on singletons")end

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:

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 workGame:includes(Singleton, ...) -- the ... means 'parameters for creating the game instance, if any'

Finally, a couple comments about nomenclature - These are just recommendations, feel free to not adhere to them.
• 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.

This evening I'll make the two code changes in MiddleClass, and I'll add one Naming convention section to the wiki.
When I write def I mean function.