CommandSignal

8 views
Skip to first unread message

Joel Hooks

unread,
Jan 17, 2010, 10:42:50 PM1/17/10
to robo...@googlegroups.com
On Jan 17, 2010, at 11:24 AM, Stray wrote:

> I'm really intrigued by how you'd combine Signals and the CommandMap...?

http://github.com/joelhooks/signals-extensions-CommandSignal

so I avoided the CommandMap altogether. Well, more specifically I wrote and tested a full on SignalCommandMap only to hit a wall on execute. No way to tell the signal originator! So, here is a CommandSignal that will execute commands that are mapped to it. I had to couple it to robotlegs, which is a bit aggravating, but I need to get normal injections as well as the Signal VOs.

Let me know what you think!

Robert Penner

unread,
Jan 17, 2010, 11:10:22 PM1/17/10
to robo...@googlegroups.com
Could removeMappedCommand be unmapCommand instead?

> --
> You received this message because you are subscribed to the Google
> Groups "Robotlegs" group.
> To post to this group, send email to robo...@googlegroups.com
> To unsubscribe from this group, send email to
> robotlegs+...@googlegroups.com
> for support visit http://knowledge.robotlegs.org
>
>

Joel Hooks

unread,
Jan 17, 2010, 11:18:20 PM1/17/10
to robo...@googlegroups.com
Yup. That is better :)

Joel Hooks (@jhooks)
http://joelhooks.com

On Jan 17, 2010, at 10:10 PM, Robert Penner <in...@robertpenner.com>
wrote:

Robert Penner

unread,
Jan 17, 2010, 11:44:55 PM1/17/10
to robo...@googlegroups.com
Hmm... CommandSignal extends Signal but duplicates its constructor
logic. The compiler throws in super() at the top, ya know. =)


On Sun, Jan 17, 2010 at 7:42 PM, Joel Hooks <joel...@gmail.com> wrote:

Robert Penner

unread,
Jan 17, 2010, 11:53:25 PM1/17/10
to robo...@googlegroups.com
This code looks sketchy (CommandSignal line 91):

if ( oneShotCommands.lastIndexOf( command ) )
{
oneShotCommands.splice( oneShotCommands.lastIndexOf( command ), 1 );


If the index is 0, the command won't be removed.
If the index is -1, splice() with remove the last element in the array.

I got bit by the -1 indexOf() and splice() combination already today:

http://github.com/robertpenner/as3-signals/commit/7112fd8da90205ec3a36642dcfef4293df94629f

Joel Hooks

unread,
Jan 17, 2010, 11:54:05 PM1/17/10
to robo...@googlegroups.com
You can't use apply on super, at least I wasn't able to get it to
work. I didn't want to reimplement the whole of a Signal. What would
you do about it?

Joel Hooks (@jhooks)
http://joelhooks.com

On Jan 17, 2010, at 10:44 PM, Robert Penner <in...@robertpenner.com>
wrote:

> Hmm... CommandSignal extends Signal but duplicates its constructor

Joel Hooks

unread,
Jan 17, 2010, 11:55:28 PM1/17/10
to robo...@googlegroups.com
Ya total oversight there. It is supposed to have the < -1

Joel Hooks (@jhooks)
http://joelhooks.com

On Jan 17, 2010, at 10:53 PM, Robert Penner <in...@robertpenner.com>
wrote:

> This code looks sketchy (CommandSignal line 91):
>
> if ( oneShotCommands.lastIndexOf( command ) )
> {
> oneShotCommands.splice( oneShotCommands.lastIndexOf( command ),
> 1 );
>
>
> If the index is 0, the command won't be removed.
> If the index is -1, splice() with remove the last element in the
> array.
>
> I got bit by the -1 indexOf() and splice() combination already today:
>
> http://github.com/robertpenner/as3-signals/commit/7112fd8da90205ec3a36642dcfef4293df94629f
>
>
>
> On Sun, Jan 17, 2010 at 8:44 PM, Robert Penner
> <in...@robertpenner.com> wrote:
>> Hmm... CommandSignal extends Signal but duplicates its constructor
>> logic. The compiler throws in super() at the top, ya know. =)
>>
>>
>> On Sun, Jan 17, 2010 at 7:42 PM, Joel Hooks <joel...@gmail.com>
>> wrote:
>>> http://github.com/joelhooks/signals-extensions-CommandSignal
>>>
>>> so I avoided the CommandMap altogether. Well, more specifically I
>>> wrote and tested a full on SignalCommandMap only to hit a wall on
>>> execute. No way to tell the signal originator! So, here is a
>>> CommandSignal that will execute commands that are mapped to it. I
>>> had to couple it to robotlegs, which is a bit aggravating, but I
>>> need to get normal injections as well as the Signal VOs.
>>>
>>> Let me know what you think!
>>

Robert Penner

unread,
Jan 18, 2010, 12:02:19 AM1/18/10
to robo...@googlegroups.com
Oh snap, you're right. Sorry for the snark.

I'll try moving the constructor logic into an init(valueClasses:Array) method.

Joel Hooks

unread,
Jan 18, 2010, 12:05:45 AM1/18/10
to robo...@googlegroups.com
looking at it I don't think it matters. In fact, if I explicitly call super() and don't do the var inits super() won't get past the _valueClasses guard. Not optimum though. The logic should probably be someplace else anyway, but it is touchy there since you want to eval the array for bad inputs...

Joel Hooks

unread,
Jan 18, 2010, 12:28:47 AM1/18/10
to robo...@googlegroups.com
By the way, this was my first time to use ASUnit4. I am *amazed* at the lightening speed of the thing. Nice.

On Jan 17, 2010, at 11:02 PM, Robert Penner wrote:

Robert Penner

unread,
Jan 18, 2010, 12:32:40 AM1/18/10
to robo...@googlegroups.com
Thanks! I haven't yet profiled AsUnit 4 to optimize specific parts,
but I built it with simple, minimal code.

Robert Penner

unread,
Jan 18, 2010, 12:44:46 AM1/18/10
to robo...@googlegroups.com
After a few iterations, I committed a fix for Signal here:

http://github.com/robertpenner/as3-signals/commit/a4b2a6b6478a22a341f9ffcd698f086f9d374465

Your CommandSignal constructor can now do this (I tried it):

public function CommandSignal(...valueClasses)
{
super(valueClasses);
verifiedCommandClasses = new Dictionary( false );
mappedCommands = [];
oneShotCommands = [];

Joel Hooks

unread,
Jan 18, 2010, 1:02:56 AM1/18/10
to robo...@googlegroups.com
that's better. I went ahead and made the amps dictionaries to avoid the splicing altogether. I also refactored the interface methods as per your request.

Robert Penner

unread,
Jan 18, 2010, 2:47:30 PM1/18/10
to robo...@googlegroups.com
I don't like having the mapper inherit from Signal, and having to use
a special class CommandSignal. I want the map to be usable with any
ISignal.

I took your code and formed a SignalCommandMap:

http://github.com/robertpenner/signals-extensions-CommandSignal/commit/8c9b57a04c44cde4ae5eaaeb8acf81c2ca7e5eee

It passes most of your tests. The two tests I commented out are
features that I'm not sure are necessary with my approach.

I used injector.instantiate() so I can use constructor injection into commands.

Joel Hooks

unread,
Jan 18, 2010, 3:08:15 PM1/18/10
to robo...@googlegroups.com
When I had the SignalCommandMap I also created a SignalContext to facilitate the initial bootstrapping. I think I will add that in here as well.

[var callback:Function = function(a:*=null, b:*=null, c:*=null, d:*=null, e:*=null, f:*=null, g:*=null):void

Is this to facilitate a finite number of valueObjects? I dig the routeSignalToCommand approach, and I am a little sad that I missed it as it was staring me in the face. I think it is the a,b,c,d,e,f,g that was throwing me off from finding the solution.

I'm going to move it back into the robotlegs namespace, as I think that is a better spot for it.

Thanks for making it proper! I like this waaay better.

Robert Penner

unread,
Jan 18, 2010, 3:45:16 PM1/18/10
to robo...@googlegroups.com
The reason for a,b,c,b,d,e,f,g is that the Signal checks the number of
arguments in the listener.
If callback used ...args, callback.length would be either 0 or 1
(can't remember).
If the Signal is set to dispatch two value objects, it's going to
complain that there aren't enough arguments in callback.

I ran into this issue while building AsUnit 4. Check this out:

http://github.com/robertpenner/asunit/blob/freerunner/as3/src/asunit4/async/TimeoutCommand.as#L47

protected function wrapHandlerWithCorrectNumberOfArgs():Function
{
switch (handler.length)
{
case 0: return function():* { return callback(); };
case 1: return function(a:*=null):* { return callback(a); };
case 2: return function(a:*=null, b:*=null):* { return callback(a, b); };
case 3: return function(a:*=null, b:*=null, c:*=null):* { return
callback(a, b, c); };
case 4: return function(a:*=null, b:*=null, c:*=null, d:*=null):* {
return callback(a, b, c, d); };
case 5: return function(a:*=null, b:*=null, c:*=null, d:*=null,
e:*=null):* { return callback(a, b, c, d, e); };
case 6: return function(a:*=null, b:*=null, c:*=null, d:*=null,
e:*=null, f:*=null):* { return callback(a, b, c, d, e, f); };
case 7: return function(a:*=null, b:*=null, c:*=null, d:*=null,
e:*=null, f:*=null, g:*=null):* { return callback(a, b, c, d, e, f,
g); };
case 8: return function(a:*=null, b:*=null, c:*=null, d:*=null,
e:*=null, f:*=null, g:*=null, h:*=null):* { return callback(a, b, c,
d, e, f, g, h); };
case 9: return function(a:*=null, b:*=null, c:*=null, d:*=null,
e:*=null, f:*=null, g:*=null, h:*=null, i:*=null):* { return
callback(a, b, c, d, e, f, g, h, i); };
}
return callback;
}

I didn't feel the need to go to that level of precision in SignalCommandMap.

Joel Hooks

unread,
Jan 18, 2010, 5:29:25 PM1/18/10
to robo...@googlegroups.com
It is essentially what Till (and everybody else in the automated DI world) is up against with cstr injection. The arg pyramid. Good times.

here's a concern I have, and it relates to the removal of the multiple commands fired test. Right now, it is going to overwrite a signal mapping with a command class in mapSignal. i think it needs to be able to map a single signal to several commands. The Robotlegs CommandMap is guarding against overwriting of commands currently, so I am thinking that SignalCommandMap should do the same, as well as allow for multiple commands per signal instance.

I typed the above a few hours ago, check out the commit and see what you think.

http://github.com/joelhooks/signals-extensions-CommandSignal/commit/51c1374847c3205388ad8e784c321a763f922aac

Joel Hooks

unread,
Jan 18, 2010, 5:44:17 PM1/18/10
to robo...@googlegroups.com
I don't like that it is tied to an instance of a signal. It is kinda gross in the startup. I'm thinking the SignalCommandMap can go ahead and map the ISignal class and create the first instance. Problem there is you screw plain old ISignals that simply extend Signal I guess.

On Jan 18, 2010, at 2:45 PM, Robert Penner wrote:

Stray

unread,
Jan 20, 2010, 4:32:43 PM1/20/10
to robo...@googlegroups.com
Looking good Joel - sorry, only just getting a chance to look at this as that 3D book is totally kicking my ass.

So - how stable is this baby? Can I use it in production code? Anything still need work?

Stray

unread,
Jan 20, 2010, 4:40:16 PM1/20/10
to robo...@googlegroups.com
Bjsus.

Just had a proper look at this - went through your tests. It's genius!

Rob / Joel - I cannot imagine the Event pain that is going to be relieved.

Amazing. Can't wait to start using it (in the next couple of days I hope).

Thanks!

Joel Hooks

unread,
Jan 20, 2010, 4:46:35 PM1/20/10
to robo...@googlegroups.com
I'd use it. The only sort of odd bits are related to the injection mapping. If you map a signal instance (mapSignal) it maps that signal instance to the command class. if you map a signal class (mapSignalClass) it creates an instance of the signal, maps that instance value to the IInjector, and marks the instance so if you map additional commands they are against the same instance. If you map a class that has already been mapped as an instance, it will use that instance. Does that make sense?

Stray

unread,
Jan 20, 2010, 4:50:46 PM1/20/10
to robo...@googlegroups.com
That makes perfect sense. Fab - I'll crack on with using it then!

sentientpen

unread,
Jan 23, 2010, 4:33:34 PM1/23/10
to Robotlegs AS3
Ok, so I'm not understanding something here. I'm using mapSignalClass
to map a signal class to a command class. Done. Now how would I
"dispatch" this signal from say, a mediator? I am looking forward to
getting rid of events once and for all! Thanks!

On Jan 20, 3:50 pm, Stray <dailystray...@googlemail.com> wrote:
> That makes perfect sense. Fab - I'll crack on with using it then!
>
> On 20 Jan 2010, at 21:46, Joel Hooks wrote:
>
>
>
> > I'd use it. The only sort of odd bits are related to the injection mapping. If you map a signal instance (mapSignal) it maps that signal instance to the command class. if you map a signal class (mapSignalClass) it creates an instance of the signal, maps that instance value to the IInjector, and marks the instance so if you map additional commands they are against the same instance. If you map a class that has already been mapped as an instance, it will use that instance. Does that make sense?
> > On Jan 20, 2010, at 3:32 PM, Stray wrote:
>
> >> Looking good Joel - sorry, only just getting a chance to look at this as that 3D book is totally kicking my ass.
>
> >> So - how stable is this baby? Can I use it in production code?  Anything still need work?
>
> >> On 18 Jan 2010, at 22:44, Joel Hooks wrote:
>
> >>> I don't like that it is tied to an instance of a signal. It is kinda gross in the startup. I'm thinking the SignalCommandMap can go ahead and map the ISignal class and create the first instance. Problem there is you screw plain old ISignals that simply extend Signal I guess.
>
> >>> On Jan 18, 2010, at 2:45 PM, Robert Penner wrote:
>
> >>>> The reason for a,b,c,b,d,e,f,g is that the Signal checks the number of
> >>>> arguments in the listener.
> >>>> If callback used ...args, callback.length would be either 0 or 1
> >>>> (can't remember).
> >>>> If the Signal is set to dispatch two value objects, it's going to
> >>>> complain that there aren't enough arguments in callback.
>
> >>>> I ran into this issue while building AsUnit 4. Check this out:
>

> >>>>http://github.com/robertpenner/asunit/blob/freerunner/as3/src/asunit4...


>
> >>>> protected function wrapHandlerWithCorrectNumberOfArgs():Function
> >>>> {
> >>>>        switch (handler.length)
> >>>>        {
> >>>>                case 0: return function():* { return callback(); };
> >>>>                case 1: return function(a:*=null):* { return callback(a); };
> >>>>                case 2: return function(a:*=null, b:*=null):* { return callback(a, b); };
> >>>>                case 3: return function(a:*=null, b:*=null, c:*=null):* { return
> >>>> callback(a, b, c); };
> >>>>                case 4: return function(a:*=null, b:*=null, c:*=null, d:*=null):* {
> >>>> return callback(a, b, c, d); };
> >>>>                case 5: return function(a:*=null, b:*=null, c:*=null, d:*=null,
> >>>> e:*=null):* { return callback(a, b, c, d, e); };
> >>>>                case 6: return function(a:*=null, b:*=null, c:*=null, d:*=null,
> >>>> e:*=null, f:*=null):* { return callback(a, b, c, d, e, f); };
> >>>>                case 7: return function(a:*=null, b:*=null, c:*=null, d:*=null,
> >>>> e:*=null, f:*=null, g:*=null):* { return callback(a, b, c, d, e, f,
> >>>> g); };
> >>>>                case 8: return function(a:*=null, b:*=null, c:*=null, d:*=null,
> >>>> e:*=null, f:*=null, g:*=null, h:*=null):* { return callback(a, b, c,
> >>>> d, e, f, g, h); };
> >>>>                case 9: return function(a:*=null, b:*=null, c:*=null, d:*=null,
> >>>> e:*=null, f:*=null, g:*=null, h:*=null, i:*=null):* { return
> >>>> callback(a, b, c, d, e, f, g, h, i); };
> >>>>        }
> >>>>        return callback;
> >>>> }
>
> >>>> I didn't feel the need to go to that level of precision in SignalCommandMap.
>

> >>>> On Mon, Jan 18, 2010 at 12:08 PM, Joel Hooks <joelho...@gmail.com> wrote:
> >>>>> When I had the SignalCommandMap I also created a SignalContext to facilitate the initial bootstrapping. I think I will add that in here as well.
>
> >>>>> [var callback:Function = function(a:*=null, b:*=null, c:*=null, d:*=null, e:*=null, f:*=null, g:*=null):void
>
> >>>>> Is this to facilitate a finite number of valueObjects? I dig the routeSignalToCommand approach, and I am a little sad that I missed it as it was staring me in the face. I think it is the a,b,c,d,e,f,g that was throwing me off from finding the solution.
>
> >>>>> I'm going to move it back into the robotlegs namespace, as I think that is a better spot for it.
>
> >>>>> Thanks for making it proper! I like this waaay better.
>
> >>>>> On Jan 18, 2010, at 1:47 PM, Robert Penner wrote:
>
> >>>>>> I don't like having the mapper inherit from Signal, and having to use

> >>>>>> a special classCommandSignal. I want the map to be usable with any


> >>>>>> ISignal.
>
> >>>>>> I took your code and formed a SignalCommandMap:
>

> >>>>>>http://github.com/robertpenner/signals-extensions-CommandSignal/commi...


>
> >>>>>> It passes most of your tests. The two tests I commented out are
> >>>>>> features that I'm not sure are necessary with my approach.
>
> >>>>>> I used injector.instantiate() so I can use constructor injection into commands.
>

> >>>>>> On Sun, Jan 17, 2010 at 7:42 PM, Joel Hooks <joelho...@gmail.com> wrote:
> >>>>>>> On Jan 17, 2010, at 11:24 AM, Stray wrote:
>
> >>>>>>>> I'm really intrigued by how you'd combine Signals and the CommandMap...?
>
> >>>>>>>http://github.com/joelhooks/signals-extensions-CommandSignal
>

> >>>>>>> so I avoided the CommandMap altogether. Well, more specifically I wrote and tested a full on SignalCommandMap only to hit a wall on execute. No way to tell the signal originator! So, here is aCommandSignalthat will execute commands that are mapped to it. I had to couple it to robotlegs, which is a bit aggravating, but I need to get normal injections as well as the Signal VOs.


>
> >>>>>>> Let me know what you think!
> >>>>>>> --
> >>>>>>> You received this message because you are subscribed to the Google
> >>>>>>> Groups "Robotlegs" group.
> >>>>>>> To post to this group, send email to robo...@googlegroups.com
> >>>>>>> To unsubscribe from this group, send email to
> >>>>>>> robotlegs+...@googlegroups.com

> >>>>>>> for support visithttp://knowledge.robotlegs.org


>
> >>>>>> --
> >>>>>> You received this message because you are subscribed to the Google
> >>>>>> Groups "Robotlegs" group.
> >>>>>> To post to this group, send email to robo...@googlegroups.com
> >>>>>> To unsubscribe from this group, send email to
> >>>>>> robotlegs+...@googlegroups.com

> >>>>>> for support visithttp://knowledge.robotlegs.org


>
> >>>>> --
> >>>>> You received this message because you are subscribed to the Google
> >>>>> Groups "Robotlegs" group.
> >>>>> To post to this group, send email to robo...@googlegroups.com
> >>>>> To unsubscribe from this group, send email to
> >>>>> robotlegs+...@googlegroups.com

> >>>>> for support visithttp://knowledge.robotlegs.org


>
> >>>> --
> >>>> You received this message because you are subscribed to the Google
> >>>> Groups "Robotlegs" group.
> >>>> To post to this group, send email to robo...@googlegroups.com
> >>>> To unsubscribe from this group, send email to
> >>>> robotlegs+...@googlegroups.com

> >>>> for support visithttp://knowledge.robotlegs.org


>
> >>> --
> >>> You received this message because you are subscribed to the Google
> >>> Groups "Robotlegs" group.
> >>> To post to this group, send email to robo...@googlegroups.com
> >>> To unsubscribe from this group, send email to
> >>> robotlegs+...@googlegroups.com

> >>> for support visithttp://knowledge.robotlegs.org


>
> >> --
> >> You received this message because you are subscribed to the Google
> >> Groups "Robotlegs" group.
> >> To post to this group, send email to robo...@googlegroups.com
> >> To unsubscribe from this group, send email to
> >> robotlegs+...@googlegroups.com

> >> for support visithttp://knowledge.robotlegs.org

Joel Hooks

unread,
Jan 23, 2010, 4:50:15 PM1/23/10
to robo...@googlegroups.com
when you map a signal class it creates and maps an instance of that class, so simply inject your signal class any where you need it. I recommend extending signal and not mapping Signal, as you will only have one instance available. It might call for a named property for injection (as an option) to sort this particular problem/limitation out.

Stray

unread,
Jan 25, 2010, 6:48:03 AM1/25/10
to robo...@googlegroups.com
ModuleContext has inbuilt modular goodies.

SignalContext has the gubbins for using as3signals...

What do people think about how best to combine them?

I don't want to wind up having to cast stuff from ModuleContext to SignalContext on the fly.

Is it cool to add the ISignalContext support to ModuleContext?

Does it mix stuff up too much?

Should ModuleContext extend SignalContext? Dependency tree... yukness.

Ideas / opinions welcome...

Joel Hooks

unread,
Jan 25, 2010, 11:28:04 AM1/25/10
to Robotlegs AS3
I would have my concrete Context implement ISignalContext. I don't
think you'd want to have either library tied to the other.

Stray

unread,
Jan 25, 2010, 12:40:09 PM1/25/10
to robo...@googlegroups.com
You're probably right there.

My problem is that the ModuleContext has a bunch of stuff in it, and SignalContext has a bunch of stuff in it... and it doesn't feel very DRY to have all that code in every concrete context. I guess I could do a single ModuleSignalContext and extend it. Casting is looking worryingly imminent though...

Reply all
Reply to author
Forward
0 new messages