middleclass & extras: middleclass 3.0 is out!

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by kikito »

Robin wrote:With the most recent GitHub version, :include() returns nil.
It should not

Try executing git submodule update.
Robin wrote:EDIT: also, there doesn't seem to be a :getCurrentState() function or the like, but I want use states for callbacks. Is there a non-hackish solution for this?
That is normally not the way you should use states. There's a method called getCurrentStateName (returns a string).

What do you intend to do, exactly?
When I write def I mean function.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by Robin »

kikito wrote:
Robin wrote:With the most recent GitHub version, :include() returns nil.
It should not

Try executing git submodule update.
Oh, it turns out I wasn't as up to date as I thought after all. Sorry. :oops:
kikito wrote:That is normally not the way you should use states. There's a method called getCurrentStateName (returns a string).

What do you intend to do, exactly?
I know about getCurrentStateName, but I want the game state to contain functions to which the love callback would refer.
Help us help you: attach a .love.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by kikito »

Robin wrote:I know about getCurrentStateName, but I want the game state to contain functions to which the love callback would refer.
I gathered that you wanted to do something like that. But I don't understand why. I mean, if you need a reference to the method 'foo' when the game is in state 'State' inside love.update, you could do this:

Code: Select all

function love.update(dt)
  game:foo() -- the State:foo function will be called when game is on the state 'State'
end
But you probably already knew this. Why is it that you can't use this pattern?
When I write def I mean function.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by Robin »

:shock:

I sure feel dumb now.
Help us help you: attach a .love.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by kikito »

:nyu:

What are you doing, by the way? Any chance of seeing it somewhere?
When I write def I mean function.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by Robin »

kikito wrote:What are you doing, by the way?
A game.
kikito wrote:Any chance of seeing it somewhere?
Oh, you will. Just not yet. ;)
Help us help you: attach a .love.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by kikito »

Small update.

Robin pointed up that I was doing something stupid with the git submodules inside middleclass-extras (the middleclass repository url was not the 'public' one, so it worked allright on my machine but no one else could get it correctly - duh). That is fixed now.

I've also just finished doing a change to the Callbacks module.

This one has been by far the most difficult one to nail, but it is reasonably working now so I wanted to share it with the world.

The callbacks module allows you to 'hook' functions to existing functions.

Quick look:

Code: Select all

Human = class('Human'):include(Callbacks)
function Human:brushTeeth() print('Brushing teeth') end
function Human:sleep() print('ZZZ') end
Human:addCallback('before', 'sleep', 'brushTeeth') -- the last param can also be a function

local peter = Human:new()
peter:sleep() -- normal call, prints ZZZ
peter:sleepWithCallbacks() -- prints 'Brushing teeth' and then 'ZZZ'
I hope it is easy enough to understand. Now the nice part: it works ok with inheritance:

Code: Select all

Soldier = class('Soldier', Human) -- subclass of human
function Soldier:haveNightmare() print('Having nightmare') end
Soldier:addCallback('before', 'sleep', function(soldier) print('Putting gun under pillow') end) -- add another callback before
Soldier:addCallback('after', 'sleep', 'haveNightmare') -- and also one callback after
local huck = Soldier:new()
huck:sleepWithCallbacks() -- prints 'Putting gun under pillow', 'Brushing teeth', 'ZZZ', 'Having nightmare'
Callbacks can also be used to interrupt or cancel the execution of a method: any callback returning false will stop the execution of the 'xxxWithCallbacks' method and immediately return false.

Also, initialize and destroy are special: they are always executed with callbacks. This is very useful for implementing fun stuff; the Apply module, for example, uses the Callbacks module to 'register' and 'unregister' items from the 'class list' automatically, without the user having to worry about it. Which is cool.

So yeah, last weekend was supposed to be the 'start pumping up documentation' weekend, but at the end I decided to continue doing this fun stuff. :nyu:

I'm even considering making another change - getting rid of the xxxWithCallbacks and adding a xxxWithoutCallbacks instead. Which option do you prefer?
When I write def I mean function.
User avatar
TechnoCat
Inner party member
Posts: 1611
Joined: Thu Jul 30, 2009 12:31 am
Location: Milwaukee, WI
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by TechnoCat »

kikito wrote:

Code: Select all

Human = class('Human'):include(Callbacks)
function Human:brushTeeth() print('Brushing teeth') end
function Human:sleep() print('ZZZ') end
Human:addCallback('before', 'sleep', 'brushTeeth') -- the last param can also be a function

local peter = Human:new()
peter:sleep() -- normal call, prints ZZZ
peter:sleepWithCallbacks() -- prints 'Brushing teeth' and then 'ZZZ'
I hope it is easy enough to understand. Now the nice part: it works ok with inheritance:
Took me quite a few reads to figure out what was going on. The fact everything being passed in was a string was throwing me off.

Code: Select all

Human:addCallback('before', 'sleep', 'brushTeeth')
param1: string. when the callback is called. before/after
param2: function pointer. the function that is calling the callback.
param3: function pointer. the callback.
kikito wrote:Also, initialize and destroy are special: they are always executed with callbacks. This is very useful for implementing fun stuff; the Apply module, for example, uses the Callbacks module to 'register' and 'unregister' items from the 'class list' automatically, without the user having to worry about it. Which is cool.
I still don't get this though.
kikito wrote:I'm even considering making another change - getting rid of the xxxWithCallbacks and adding a xxxWithoutCallbacks instead. Which option do you prefer?
I think xxxWithoutCallbacks is more useful. More useful because I believe it would be less used that is.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by kikito »

TechnoCat wrote: Took me quite a few reads to figure out what was going on. The fact everything being passed in was a string was throwing me off.

Code: Select all

Human:addCallback('before', 'sleep', 'brushTeeth')
param1: string. when the callback is called. before/after
param2: function pointer. the function that is calling the callback.
param3: function pointer. the callback.
param1 must be either the string 'before' or the string 'after'. Can't be anything else.
param2 is a method name. It can exist, or it can be a not (yet) existing method.
param3 is a callback, but can be either a method name ("pointer" as you called it) or a normal lua function (first param must be the instance -'self')
TechnoCat wrote:
kikito wrote:Also, initialize and destroy are special: they are always executed with callbacks. This is very useful for implementing fun stuff; the Apply module, for example, uses the Callbacks module to 'register' and 'unregister' items from the 'class list' automatically, without the user having to worry about it. Which is cool.
I still don't get this though.
This means that there's no 'initializeWithCallbacks' and 'destroyWithCallbacks' - destroy and initialize always use their callbacks. This is useful for making mixins because very often you need mixins to do stuff with your objects, independently from the user. The Apply mixin allows a class to 'invoke a method in all its instances'. So if you want to invoke the 'pause' method in all the instances of the class Goblin, you do something like this:

Code: Select all

 Goblin = class('Goblin'):extends(Apply)
local goblin1, goblin2, goblin3 = Goblin(), Goblin(), Goblin() -- create 3 goblins
-- invoke 'sleep' in all instances of goblin:
Goblin:apply('sleep') 
In order to do that, you have to store references to all instances of each class on some 'instance list'. Without callbacks, the lib would have to provide means for the initializers/destroyers to manually 'register' and 'unregister' each instance. In other words, the lib user would be forced to invoke something like this:

Code: Select all

function Goblin:initialize()
  super.initialize(self)
  self:registerInClassList() -- provided by apply
end
function Goblin:destroy()
  super.destroy(self)
  self:unregisterFromClassList() -- provided by apply
end
By making initialize and destroy 'special' for the callbacks module, this is done 'transparently'; the Apply module calls the register / unregister methods transparently. So it gets simpler and less error-prone.
TechnoCat wrote:
kikito wrote:I'm even considering making another change - getting rid of the xxxWithCallbacks and adding a xxxWithoutCallbacks instead. Which option do you prefer?
I think xxxWithoutCallbacks is more useful. More useful because I believe it would be less used that is.
Yeah, me too. The xxxWithCallbacks was simpler to implement :3 But I'll give it a try, because the xxxWithoutCallbacks sounds even more 'transparent'; and most importantly, 'initialize' and 'destroy' could stop being 'special'.
When I write def I mean function.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: middleclass & middleclass-extras: Object Orientation for

Post by Robin »

Very interesting.
kikito wrote:Yeah, me too. The xxxWithCallbacks was simpler to implement :3 But I'll give it a try, because the xxxWithoutCallbacks sounds even more 'transparent'; and most importantly, 'initialize' and 'destroy' could stop being 'special'.
Yes, a very good idea. Although I'm wondering if there's a cleaner way to do it. Having to call xxxWith(out)Callbacks seems a bit hackish.
Help us help you: attach a .love.
Post Reply

Who is online

Users browsing this forum: No registered users and 7 guests