Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Show Posts

* | |

  Show Posts
Pages: [1] 2
1  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: May 19, 2009, 03:52:36
I am saying that if you require that a command mods a notification in order for the next command to work, you are indeed introducing a coupling between the commands that didn't previously exist. You cannot now introduce 'any' command into the sequence - for example a command that expects a certain VO as its note body (say). It must be a command designed to consume the array of (whatever - proxies in this case).

Whereas, if you have a variation of addSubCommand() that can pass in params (or not, as required) then the subcommands remain quite ignorant of each other's existence, and so can be re-used freely and intermixed with one another in other macro commands or used standalone, without imposing the requirement that they handle the note body in a certain way.

Will
2  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: May 11, 2009, 03:56:56
don't forget that commands can modify just the notification if needed

The trouble with commands modding the notification is that it means that the command becomes 'aware' of its context. This is also my problem with eating the array of parameters as you go along. It works, but you are spreading knowledge of the parameter mechanism, and the outside environment, into the sub command. The subcommands become more tightly coupled than one wants.

And yes, I would like to come back and have a go at this and a few other things. There are some straightforward mods that I made to to the State machine which I claim improves its decoupling considerably. I would like to share, if Cliff is up for it.

But not today.  Today I am on a code death march! :-o

Will


3  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: May 11, 2009, 01:20:41
In a similar situation recently, I thought of this approach - sending in an array and modifying it - and I would certainly expect it to work.

But I can't help feeling a mod to addSubCommand() would be clearer, though, and more generally applicable. There seems no reason AFAIK why subcommands should not take parameters. It would make them generally more useful and powerful.

Will
4  PureMVC Manifold / Standard Version / Re: handleNotification and order on: April 01, 2009, 02:26:42
for some reason I can see that the trace is showing that the notifications within the models are firing in this order

mB - E1
mB - E2
mA - E2
mA - E1

[...]

Is this at all normal?
I think so, yes. Without reading the code I guess:

When you send a notification, it isn't queued, but processed by PureMVC immediately.

So when mB sends E2, everything that handles E2 is going to handle it before sendNotification(E2) returns in mB, and mB returns control to the framework. So only when mB finishes handling E1 can any other class get a chance to handle it.

If you want everything to handle E1 followed by everything handling E2, you could make a new command that sends E1 followed by E2. It isn't clear to me what you want to happen, and therefore difficult to advise you.

Will
5  Announcements and General Discussion / General Discussion / Re: FSM Uses & Limitations / Async transitions on: April 01, 2009, 02:11:57
(I do think Jason's comment is to the point. This is a confusing area. To minimise confusion, I will refer to app-states and vis-states to distinguish the two kinds.)

You can map FSM app-states to visual change vis-states.

For example, you could treat your periods of tweening as app-states in themselves, and give them names like 'XXXChanging'. You enter XXXChanging when you start the tweening effect, and exit it when it finishes. You end up with three app-states (XXXBefore, XXXChanging and XXXAfter) mapping to two vis-states (XXXBefore and XXXAfter).

Or you could decide that mapping these transitional periods to FSM app-states serves no particular purpose, and consider the transitional tweening period to be part of either the starting or, more likely, finishing app-state.

Which technique you use depends on how you intend to use you FSM. The point of the FSM is to orchestrate different parts of you application. If you need to do extra things on both starting and finishing a vis-transition, then you need to consider the more fine-grained approach. If (say) nothing else needs to know when the tweening finishes, it would not be worth modelling... and indeed provides a useful simplification to your FSM model. (In my experience FSMs rapidly get too large and complex.)

Also, if you take the fine-grained approach, essentially you are writing code and doing work to synchronise two bits of application state. To me this has what the refactoring people call 'a smell'.

If you build your intended FSM model first, you may find this clarifies your view of this sort of detail. I think the State Machine Compiler site http://smc.sourceforge.net/ has lots of good material on the general application of state machines.

Will
6  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: March 18, 2009, 03:01:09
@Cliff: Excellent news that we have resolved this - I was afraid that one or both of us was going mad!

On the general discussion: certainly AsyncCommand and macdaddy (much improved terminology) have the drawbacks that you say. I have not used a macdaddy yet, and expect its application to be quite limited, for the sorts of reasons you say. But I can imagine wanting to make a McSimpleCommand sandwich: say a Simple followed by an Async followed by another Simple.

AsyncCommand I have found to be good in two use cases: calling services, and also for handling modal dialogs.

Modal dialogs don't block the thread, but they do something rather like it, by restricting the user typically to Ok and Cancel buttons. So you get something very like the blocking behaviour. If you have the initial part of an AsyncCommand launch the modal dialog, and have the completion part process the result and take appropriate action, then you have all the logic for your dialog handling neatly localised in one place.

Calling services with AsyncCommand I have discussed at length, I know. But you may have missed my point that using AsyncCommands in this way enables you to remove the notification constants declared in proxies. Why would one want to do this? Because it means that mediators that depend on data from the proxies wrapped up in a VO don't need to import the proxy. Sure, the AsyncCommand does, but it would do so anyway. It means one doesn't have to hunt through proxies for notification constants too.

The drawbacks you mention to AsyncCommands are mostly true (although I have no 'tedious coordination of chained commands', honest), but if you plan for them you discover they may not matter. If the data arrives too late because the punter has changed his mind, then so what? If your app continues to be responsive, even at the hands of an impatient clicky user and a slow data feed, then that is a win.

The main drawback with the approach based on states is: when I tried it I ended up with a LOT of states, in order to cope with all the 'waiting for an answer' situations I needed to handle. I found this was clouding my view of how the whole machine worked. I want to keep the state machine only for very high level features; I found I could push a lot of detail into AsyncCommands and hide it there.

This is of course all extremely subjective and Your Mileage May Vary.

I do feel pretty bullish about the way I have got my app organised. Of course the bedrock is the base PureMVC architecture, which has proved great. I mention this because you may think I lose sight of this point in the heat of discussion - I don't.

Will
7  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: March 17, 2009, 03:21:53
So, when you finally call commandComplete on an AsyncCommand, what exactly is it that you wish to happen? If it is not a subcommand of an AsyncMacroCommand, its like the sound of one hand clapping. It signifies nothing. No one is listening.
I don't understand why we are struggling with this so much, because it really, really isn't very hard. I must be putting my point over really badly.

Let's break it into steps, and see if we can't identify the point where we diverge

1. AsyncCommand is a convenient wrapper for any process that completes asynchronously. Ok? You may not approve of its use, but that's how I use it, in fact using a design of your suggestion - which works very well for me. See first para here:
When you invoke the Proxy method to make the remote call, pass a Function typed reference[...]

2. When the remote call returns control to the proxy, it uses a callback to raise the second part of the AsyncCommand, just as suggested in your design.

3. The second part of AsyncCommand completes its business. Typically it emits a notification.

4. Finally, because this AsyncCommand doesn't know whether or not it is part of a macro, it must call commandComplete(). I repeat: it does not know whether it is a subcommand or standalone. So the whole business of 'one hand clapping' does not arise. It doesn't care whether it has a parent or not; it just knows that it must notify a parent if it happens to exist. So commandComplete() mustn't barf if it happens not to have a parent. Because it has to call commandComplete() anyway. Because it doesn't know. Pant, pant, pant ;-)

As for the thread of execution, if an AsyncMacroCommand is running, the thread is running, but in a loop in the AsyncMacro which is waiting for the subcommand to report completion. If you don't have the macro running then your thread moves on. So someone might think well I can just use the AsyncCommand and further processing will be suspended until I call commandComplete, which actually does NOTHING at all without the AsyncMacroCommand.
Sorry, but this is quite wrong. But we needn't have this as an abstract argument.

Here is the code from http://puremvc.org/pages/utils/AS3/Utility_AS3_AsyncCommand/srcview/; this is the key function from AsyncMacroCommand.as:
:
        private function nextCommand () : void
        {
            if (subCommands.length > 0)
            {
                var commandClassRef:Class    =    subCommands.shift();
                var commandInstance:Object    =    new commandClassRef();
                var isAsync:Boolean            =    commandInstance is IAsyncCommand;
               
                if (isAsync) IAsyncCommand( commandInstance ).setOnComplete( nextCommand );
                ICommand( commandInstance ).execute( note );
                if (!isAsync) nextCommand();
            }
            else
            {
                if(onComplete != null) onComplete();
               
                note         =    null;
                onComplete    =    null;
            }
        }                     
The key thing to note is that, if executing an asynchronous command, it drops out of the function. It is not in a loop! It couldn't be, otherwise nothing else could happen within the main Flash thread.
(Whereas with a simple command, it does indeed loop around, calling itself recursively. This is what this line is about:
:
                if (!isAsync) nextCommand();
but you notice it specifically excludes asynchronous commands.)

So anything can happen when an AsyncCommand or an AsyncMacroCommand is executing, and there is no difference between the two in terms of thread loops. They are both waiting for a callback.

Now (I hope) I have cleared that up for you, perhaps we are nearer to seeing eye to eye regarding how AsyncCommand works.

The other thing that is amusing to notice is that this code already contains exactly the test that I propose for AsyncCommand
:
                if(onComplete != null) onComplete();
This test is there for exactly the same reason that I suggest it: AsyncMacroCommand in turn may (or may not) be aggregated into further AsyncMacroCommands - but the code in each level doesn't 'know' whether this has happened or not.

The project page for each utility has a link to the author's page, which has their email address, so if you'd like to talk to Duncan about making this change, just send him an email.
Thanks - will investigate.

Since most service interactions end up pulling data into the client that will be used for display and or update back to the server, a long lived entity is more appropriate, which is why the best practices doc suggests use of proxy or proxy/delegate as the preferred method of handling services.
I use a proxy to handle services - as per the recommendation. I also call proxy functions from the commands. By making the command asynchronous, I found I could contain the whole business of handling the callback within the context of the command.

I tried modelling the system with state changes - ie the arrival of the data in the proxy generated a notification, which caused a state change. This worked, but I like the localisation of the service call that is provided by the AsyncCommand. By handling remote calls in a single command, nothing else has to 'handle' them.

By the way, I still use the proxies to do all the data handling. In effect, what I have done is replace the notification emitted by the proxy in classic pureMVC design by a callback to the owning AsyncCommand. This means I don't have to declare any notification string constants in proxies, and so don't have to reference the proxies in any mediators (because the notifications are emitted by the commands). So I break completely the dependency of the mediator on the proxy - it's another gain for separation of concern.

However, as you know, I am absolutely an enthusiast for state machines, and definitely advocate their use in these types of applications. There are no swamp-smelling bears in my app! :-)

Will
8  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: March 16, 2009, 12:37:23
The point is the AsycCommand is absolutely useless in any context other than as a subcommand of an AsyncMacroCommand. Its call for completion is meaningless.
You keep saying this. It just isn't the case.

An AsyncCommand 'has meaning' for example if you wrap it around a remote call. When the remote call returns, it can take appropriate action (handling failure, notifying  other participants), and finally call commandComplete().

Why would I only run the above in the context of an AsyncMacroCommand?

And the danger is that someone thinks that the thread of execution has stopped during the asych activity, which is not the case unless it is a sub of an AsyncMacroCommand. In any other setting, the thread of execution keeps right on truckin'.
Not true.

If you write asynchronous code, the thread continues executing irrespective of AsyncMacroCommand's involvment. All AsyncMacroCommand does is get control back at some point in the future and pass it to the next command.
 
Btw, I am not the author of this utility, that is Duncan Hall. You may wish to take up the question with him.

Ok, if that's the right thing to do. How do I contact him?

Will
9  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: March 14, 2009, 09:11:03
How does a standalone AsyncCommand differ from a SimpleCommand in such a way that would cause you to use it as anything other than a subcommand of an AsyncMacroCommand?

Look at it the other way round. If you have an AsyncCommand that, you realise, can be useful standalone, why should you have to duplicate its code as a SimpleCommand to use it?

or

If you design a command that is intrinsically asynchronous (eg it makes a round trip call to the server), why wouldn't you design it as an AsyncCommand rather than a SimpleCommand, and thereby reserve the opportunity to compound it into an AsyncMacroCommand if the need arises?

We seem to be making heavy weather of this. The suggested change is very cheap, and is invisible to those who don't care... but allows an expected use to work for those who do. I feel I have already written more than enough to justify it. If you don't want it, well, fair enough.

Will
10  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: March 13, 2009, 09:30:28
As I said to Tek, surely the point of having AsyncCommands is that they can be compounded into macros or not, as the need arises.

The current code prevents this. A correctly-written AsyncCommand cannot be used by itself. There is no indication in the docs to suggest that this is intentional.

The proposed correction breaks no code AFAICS. It seems uncontroversial to me.

Will


11  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: March 11, 2009, 06:00:45
To be honnest, I can't see the context where you need an AsynCommand to call *commandComplete* without to have a wrapper that declare the *onComplete* callback like in the AsynMacroCommand. But you're right, your patch will prevent any use of the AsyncCommand as a SimpleCommand.

The point is that a AsyncCommand shouldn't care whether it is being used standalone or as part of a macro. It should work either way, without needing to change its behaviour. For example, you may design an AsyncCommand to be used by itself, and subsequently add it to a macro.

Will
12  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: March 11, 2009, 05:08:30
So it's not a bug. The class do not know the logic that drive to the end of the execution of the asynchronous process, the instance have to call *onComplete* itself to notify of the end of the asynccommand execution.

1. You seem to be confusing commandComplete(), a protected method, and onComplete, a private instance variable containing a pointer to a function. It is commandComplete() that one is supposed to call - onComplete is not in scope in an inherited class.

2. Yes, it is a bug. If the inherited code (correctly) calls commandComplete() from a standalone AsyncCommand (ie not run as a macro) to notify end of execution, then onComplete is null, and the program dies.

Will
13  PureMVC Manifold / Demos and Utils / Re: AsyncCommand - A PureMVC / AS3 Utility on: March 11, 2009, 03:49:36
I think there is a bug in AsyncCommand.as.

The example code only considers AsyncCommand instances being invoked from an AsyncMacroCommand.

If an AsyncCommand is not run from an AsyncMacroCommand, then setOnComplete() is not called for that instance, and onComplete remains null. So when the code in AsyncCommand calls commandComplete() to indicate it has finished, the code barfs.

The cure, I suggest, is to test for an uninitialised onComplete member in commandComplete(), like this:
:
/**
 * Notify the parent <code>AsyncMacroCommand</code> that this command is complete.
 * <P>
 * Call this method from your subclass to signify that your asynchronous command
 * has finished.
 */
protected function commandComplete () : void
{
if (onComplete != null)
onComplete();
}

After this, AsyncCommands can be used standalone and in macros.

Will
14  Announcements and General Discussion / Getting Started / Re: AsyncCommand and remote proxies on: March 09, 2009, 03:51:05
Don't confuse the GoF State pattern with the StateMachine utility, they are completely different things.

I am not confusing them. I did prefix my remarks with
To compare with another well-known state machine design.

My point it the GoF State pattern can be considered a model implementation of a state machine. And it has a very desirable attribute - encapsulation of its actual state - that yours doesn't have.

You asserted that your implementation doesn't break any tenets of OOP. I am saying it jolly well does. I am trying very hard to get you to look again at an important design defect in the utility.

AIUI your design forces the user to test state outside the state machine. The problem with this is that you are build a dependency between the state machine itself - specifically the XML fragment that describes it - and the 'outside' code in the rest of your application. So that if you change the design of the state machine - for example splitting one current state into two - you will need to chase up all references to the state machine's state in the code that interfaces to it. To borrow and despoil your analogy, bits of the conductor have leaked out into the orchestra.

My assertion is that, as a matter of good, decoupled design, the mediators and commands that are driven by the state machine must be unaware of how the 'conductor' does his work.

What I propose is: when a given transition occurs, you optionally send out a 'effect' notification, which (probably) fires a command that performs the actions required by this transition. This is akin to the notifications sent out on entrance and exit of states, but it is tied to the transition, not to the states. Note that you can choose to have different transitions issue the same command.

Perhaps a concrete example will help. Here is a teeny bit of state machine stolen from something posted into the forum elsewhere:

:
<state name="TOP_LEFT">
<transition action="TO_TOP_RIGHT" target="TOP_RIGHT" />
</state>

<state name="TOP_RIGHT">
<transition action="TO_BOTTOM_RIGHT" target="BOTTOM_RIGHT" >
</state>
//...
It models a box that moves between the corners of the screen, but only horizontally and vertically in a clockwise direction.

To interface to this code, one is going to have to write a handler in a mediator like this (I have omitted 'ApplicationFacade.' in front of string constants throughout this stuff)
:
// In a Mediator somewhere
override public function handleNotification(note:INotification):void
{
switch (note.getName()) {
case StateMachine.CHANGED:
// Have to test the FSM's current state
if ((note.getType() == TOP_RIGHT) {
viewComponent.doMoveRight()
} else if ((note.getType() == BOTTOM_RIGHT) {
viewComponent.doMoveDown()
//...

Notice that the mediator's code 'knows' about the states TOP_RIGHT, BOTTOM_RIGHT etc, and it also 'knows' about the behaviour of the state machine. It knows that if the state machine is in the TOP_RIGHT position, it must have got there from TOP_LEFT, so doMoveRight() should be called.

Here is the FSM fragment with my proposed variation - the addition of an 'effect' attribute:
:
// FSM
<state name="TOP_LEFT">
<transition action="TO_TOP_RIGHT" target="TOP_RIGHT" effect=CMD_MOVE_RIGHT/>
</state>

<state name="TOP_RIGHT">
<transition action="TO_BOTTOM_RIGHT" target="BOTTOM_RIGHT" effect=CMD_MOVE_DOWN>
</state>
//...
And here is the code in the mediator
:
override public function handleNotification(note:INotification):void
{
switch (note.getName()) {
case CMD_MOVE_RIGHT:
// Don't care about the FSM's current state
viewComponent.doMoveRight();
break;
case CMD_MOVE_DOWN:
viewComponent.doMoveDown();
break;
//...

I hope you will agree that this is already better code. There is no need to add logic that queries the FSM's state - it simply obeys incoming commands.

So far, so good.

Now suppose that the spec changes (as I hear sometimes happens), and it is desired that the box can move clockwise and anti-clockwise. In the current utility, the state machine fragment changes like this:

:
<state name="TOP_LEFT">
<transition action="TO_TOP_RIGHT" target="TOP_RIGHT" />
<transition action="TO_BOTTOM_LEFT" target="BOTTOM_LEFT" />
</state>
//...

Notice how the code to support this changes:
:
// In a Mediator somewhere
override public function handleNotification(note:INotification):void
{
switch (note.getName()) {
case StateMachine.CHANGED:
// Have to test the FSM's current state
if ((note.getType() == TOP_RIGHT) &&
viewComponent.currentPos() == TOP_LEFT) {
viewComponent.doMoveRight();
} else ((note.getType() == TOP_RIGHT) &&
viewComponent.currentPos() == BOTTOM_RIGHT) {
viewComponent.doMoveUp();
} else // Tons more modified code here...
//...

We have to query not only the current state of the state machine but, in effect, the previous state too, which I guess will be cached in the component. (In real life, this logic should maybe be put into the component - cut me some slack on that detail). Anyway, we have to make tons of changes to accomodate the change ion the state machine.

Now my proposed altered design. Its FSM is very similar:

:
<state name="TOP_LEFT">
<transition action="TO_TOP_RIGHT" target="TOP_RIGHT" effect=CMD_MOVE_RIGHT/>
<transition action="TO_BOTTOM_LEFT" target="BOTTOM_LEFT" effect=CMD_MOVE_DOWN />
</state>
//...
And here is the code in the mediator
:
override public function handleNotification(note:INotification):void
{
switch (note.getName()) {
case CMD_MOVE_RIGHT:
// Don't care about the FSM's current state
viewComponent.doMoveRight();
break;
case CMD_MOVE_DOWN:
viewComponent.doMoveDown();
break;
//...
Yup, it's exactly the same as before. Not a line changed.

With my proposal, when you alter your state machine's internals, you do not have to change any code outside it. Nothing outside the state machine tests for any conditions, so no code beyond the XML is affected. The constants defining state names can be defined in local scope of the FSM injecting routine.

It's neat, and it works, and it is not a big change to what you have. So how about it?

I apologise for harping on. If I have misdescribed how your system works, then please put me right. But it is quite a difference.

Will

PS: 'effect' notification is what is called an 'action' in standard FSM terminology. But I don't want to go around that loop again.


15  Announcements and General Discussion / Getting Started / Re: AsyncCommand and remote proxies on: March 05, 2009, 08:17:03
WRT performing guard logic in the exiting note [...]
I'd say your position is approximately as I stated... as remains mine. I am afraid we are going to have to agree to differ on this.

As for 'never querying state' its not a query, its a notification.
It's not whether it's a query or a notification that exercises me. It is the fact - as I possibly wrongly understand it - that your mediator code must sometimes need to 'know' about states, and test conditions resulting from the state of the state machine. My impression is you worry about whether a state transition has occurred or is in progress - and I loudly say you have no business so doing.

The tenet of OO that is broken is the encapsulation of the state machine itself.

To compare with another well-known state machine design. Consider the GoF State pattern. None of the classes that interact with the outer 'wrapper' class can know what the state is inside. The thing is sealed. From the point of view of an outside observer, all you can tell is that it seems to change its behaviour.

The point is: I believe that even as you have redesigned it, a user of this library is forced to break encapsulation. However, I claim this needn't be the case, but for a quite cheap change.

Perhaps I misunderstand what you are doing. If you can present a fragment of code for an example - eg a bit of the XML and the handling of the StateMachine.CHANGED note, then we could be sure we are on the same hymn sheet.

Will

PS: Found your follow up. Be grateful you have a BlackBerry. I have a Palm Treo. It would crash long before I could post to a thread like this :-)
Pages: [1] 2