08-05-2012 11:19 PM
I didn't get to read the whole paper, but I got through the analysis of AF 3.0 and would like to comment on that part.
1."Friend" Scope for All Messages
I see the need for this in secure applications. I agree with Daklu's perspective that it's not worth worrying about in most situations. I would implement this restriction in a subclass of Actor, and designers that want to use the feature can sub from that class.
2. Different Calling Modes for Messages
I like the idea of having this already implemented in the framework. I wouldn't have to use it, but I could if I wanted to.
3. Separating Actor Functional and Message Handling Domains
I understand the conceptual benefit of separating the behaviors, but I can't think of a practical reason that justifies the extra weight it adds to the framework. It just seems to make the framework (even) more clunky and opaque.
4. Batch Messages
AQs design restriction for Batch messages was that they be atomic, otherwise they're just an aggregation and not a real Batch. I think that consideration should be honored, and they should be used carefully by a skilled developer.
5. AF Lacks Support for Pause/Resume/Cancel, etc.
I voiced my opinion in the subthread above regarding this one.
6. Dependency Inversion and Dependency Injection
I could see the utility of separating queue construction from Launch Actor.vi, and it seems like a trivial enough change. I would comment, though, that you can't enforce the use of a constructor method in LV. Trying to do so in your framework seems like a wasted effort because any developer can just drop an object constant on their diagram and do whatever they like anyway.
------------------------------------------
In general, I find AF to be powerful but "heavy". It's hard to debug without tools you have to either write yourself or pay extra for (and still needs more tools/features in the IDE that just don't exist). It has lots of features that aren't on the palettes and lacks examples outside what's on this forum. It requires a lot of "custom boilerplate" code to get an Actor object running smoothly. Tracing its behaviors through all the dispatched template methods is a real chore when debugging (especially following error response behaviors). If you intend to modify or extend it, the primary concern I would have as a user is that you do not make it still more overbearing to plug into. Try to make any features you add optional, and try to provide transparency of operatioin as much as possible.
08-06-2012 01:11 AM
DavidStaab wrote:
Putting "override actions" like Pause/Cancel/Resume into the framework seems like a make-work design that weighs on developers. I'd hate to have to override those behaviors with no-ops for every actor that I don'twant to be pausable or cancellable. I'd much rather implement them myself for any actors that I want to have those behaviors, either by creating High-priority AF 3.0 messages that supercede the "job queue" with those commands, or using a State pattern in the actor's functional logic.
David, completely agree with you - "override actions" suck big time. But in ArT_Actors you do not have to do any overrides - Pause/Resume/Cancel messages are Meta Messages and never get outside of Actor Component Get_Next_Message method, thus never get executed in Actor's Message Loop.They are handled completely within a concrete Message Transport class. But you can't obviously see that without the source code ...
As to Message Transport implementations - they are not part of ArT_Actors core (only the abstract ArT_Message_Transport class is). You can choose to configure different Actors (within an application) with whatever Transport is suitable for that Actor's purpose - eliminating the overhead. The bare bones Transport (LVQ) is just a wrapper around a LabVIEW Queue. When it gets a message - it checks that message for Scope and drops it if this is a meta message (not supported by LVQ Transport).
I supply three [optional] implementations for Message Transport out of the box, but you do not have to use them if you got your favorite one.
Same thing with Lock/Unlock - no overrides required. In fact, Lock/Unlock are not even messages. Both are plain by-value class methods executed on the calling side and are already stubbed (i.e. Lock always returns FALSE) in ArT_Actor_API base class implementation.
I saw your second response but do not have time to reply right now. If you're interested - we can talk this over in person - I plan on coming to 10 AM Actor Framework Introduction tomorrow (Monday).
Dmitry
PS: Just watched Curiosity landing on NASA TV. I rarely get emotional (if at all), but this was truly AWESOME .
08-06-2012 04:05 AM
Dmitry wrote:
DavidStaab wrote:
Putting "override actions" like Pause/Cancel/Resume into the framework seems like a make-work design that weighs on developers. I'd hate to have to override those behaviors with no-ops for every actor that I don'twant to be pausable or cancellable. I'd much rather implement them myself for any actors that I want to have those behaviors, either by creating High-priority AF 3.0 messages that supercede the "job queue" with those commands, or using a State pattern in the actor's functional logic.
David, completely agree with you - "override actions" suck big time. But in ArT_Actors you do not have to do any overrides - Pause/Resume/Cancel messages are Meta Messages and never get outside of Actor Component Get_Next_Message method, thus never get executed in Actor's Message Loop.They are handled completely within a concrete Message Transport class. But you can't obviously see that without the source code ...
How to you handle Actors with auxillery loops or who control sub-actors? Pausing the receipt of new messages in the "Get_Next_Message" method doesn't stop everything in a complex actor.
-- James
BTW, I'm am very interested in learning more about your "Topic" class; I use publish-subscribe heavily in my own messaging re-use library.
Added later: never mind, I thought you were pausing the whole operation of the actor, but I now think you just mean to pause handling of messages from outside the actor (but not messages originating from the actor itself -- am I right?).
Message was edited by: drjdpowell
08-07-2012 05:48 PM
drjdpowell wrote:
How to you handle Actors with auxillery loops or who control sub-actors? Pausing the receipt of new messages in the "Get_Next_Message" method doesn't stop everything in a complex actor.
A Composite Actor needs to override Pause/Resume/Cancel methods in it’s Composite_Actor_API class (not the Composite_Actor class !) to forward the action to each of subActors and then execute the action on itself. This should be done inside a critical section to prevent race conditions. All 3 messages shall use the same critical section to avoid interfering with one another for the same reason.
Added later: never mind, I thought you were pausing the whole operation of the actor, but I now think you just mean to pause handling of messages from outside the actor (but not messages originating from the actor itself -- am I right?).
No. Not right :
BTW, I'm am very interested in learning more about your "Topic" class; I use publish-subscribe heavily in my own messaging re-use library.
ArT_Topic is a is a very simple class:
08-08-2012 12:02 AM
I'm not grasping why you're concerned about the transmission of arbitrary messages by callers. In a non-message passing environment, any method that is public may be invoked by any caller. If a class designer does not wish a method to be universally invokable, the designer should make that method protected/private/etc. With AF, a message can only invoke methods that are either public or community scope. There's no way for a caller to create a message that would call a method that is private. Thus the things that a caller can do to the object via messages is no different than the things that a caller can do to the data directly before the object is launched.
If you are concerned about who can send the messages, the AF already limits the senders of messages -- only the caller, the actor itself and its nested actors can send any message. If the actor wishes to make messages that only itself can send to itself, that's easily done with a community scope'd method and a privately scope'd message class. Messages that only the children can send can be implemented by creating a protected scope "send" method for that privately scoped message. No, there is no mechansim to create a message that only the caller can send, but I don't see that as a real issue -- the class itself would not send a message to itself that would violate its own design. Messages that only nested actors can send isn't a case that I've considered. Generally the nested actors are either intimately aware of the caller actor and have understanding of the message purposes, or they are so divorced from the caller that there's an API contract of the messages they can send.
If you're concerned about timing of messages (i.e., certain messages can only be sent early in the launch cycle, and once some threshold event occurs, that message can never be sent more), that's more the responsibility of the actor to keep track of its state and return an error if one of those messages is sent too late.
In short, I'm not buying concern #1 "A caller can execute an arbitrary Message on Actor’s Private Data". It is -- to me -- no different than the methods a caller could call anyway and the designer should scope methods differently if he/she does not wish them to be called.
--------------
Take a non-actor LV class. Implement all of its methods. This is a pure by-value class that is as fully testable without spinning up the framework as any other. Now change it to inherit from Actor.lvclass. Now it is launchable and messageable to call those methods. Has its testability changed? No. All of those methods are still just as testable. This is why I don't see what you're goal is with separating the Actor into two separate class hierarchies, one for "this is the data" and one for "this is the message handler". If an actor is one that just does data operations upon receipt of a message, then as I see it, the change buys you nothing. But if the actor is one that, as part of handling a message, needs to respond with a message (to itself or to its caller), you've hampered the testability more than you have helped it, at least from my perspective. Can you elaborate on what your goal is with this separation? Is there any reason why any given actor could not -- without any change to AF -- encapsulate through containment another object that is its data and get the same separation, if it really is beneficial? Why the need for an explicit "data actor" hierarchy?
08-08-2012 09:36 AM
AristosQueue wrote:
This is why I don't see what you're goal is with separating the Actor into two separate class hierarchies, one for "this is the data" and one for "this is the message handler".
One possible advantage of a "message handler" class is that one could create children with things like message logging or other debug features.
08-08-2012 09:46 AM
Dmitry wrote:
A Composite Actor needs to override Pause/Resume/Cancel methods in it’s Composite_Actor_API class (not the Composite_Actor class !) to forward the action to each of subActors and then execute the action on itself. This should be done inside a critical section to prevent race conditions. All 3 messages shall use the same critical section to avoid interfering with one another for the same reason.
I'm confused here; how does the API have the ability to send messages direct to subactors? In other words, if the Actor creats a subactor, how does the address of the subactor get back to the actor's API?
No. Not right :
- Pausing an Actor @ Priority Level shall pause all messages at (and below) that level on Actor and all its subActors independent of where messages are coming from. Example – when pausing a Scanner I expect the Stage subActor to be paused too – even if Scanner sends a ‘Move' message (for whatever reason) to Stage.
- The behavior you mentioned above (delaying external messages only) is used for Locking
Ah, I confused Pausing with Locking. But the Pausing seems to be getting more complicated. How do I specify things, like safety monitering or PID-control loops, that must not be paused, even if a caller calls "pause" with a very high priority level?
Added later: Also, what about auxillery loops that aren't themselves actors? Auxillery loops to do things like wait on a TCP connection for incoming data or read out a DAQ.
Subscribing to a Topic requires sending a Subscribe request (with caller’s Reply message as data) to Publisher
Is the subscription handled by the framework, or does the User have to call "Subscription" on the Topic explicitly?
-- James
Message was edited by: drjdpowell
08-08-2012 10:20 AM
AristosQueue wrote:
This is why I don't see what you're goal is with separating the Actor into two separate class hierarchies, one for "this is the data" and one for "this is the message handler".
I can imagine advanced scenarios where it could be beneficial to have a separate message handler class. I've lightly explored them with my own (non AF) actors that are implemented as state machines. Not nearly enough to say, "yes, they are a good idea," but enough that I find the concept intriguing.
Yesterday Allen showed me how he implemented the State Pattern using AF, with each state being a separate actor. In the short time we had it looked to me to be perfectly functional. However, intuitively it makes more sense to me to change an actor's behavior by swapping message handler (or state) classes rather than swapping actors. Is there a practical difference? Probably not, but again I haven't used AF enough yet to make a claim one way or the other.
08-08-2012 10:28 AM
BTW, I like "2. Different Calling Modes for Messages". Seems to me that whether a Sender blocks or doesn't block waiting for a reply is the business of the Sender, and shouldn't be dictated by the actor making the reply. I've suggested this for the Actor Framework somewhere.
08-09-2012 09:43 AM
Daklu and drjdpowell: Both of you said why it would be valuable, but neither answered my challenge that you can already do this today. My contention is that if you want this separation in any given actor, go ahead and give your message handling actor a private data member of another class -- any class. Why do you need an explicit "inside an actor" class hierarchy?
Regarding "Different Calling Modes for Messages": No, it cannot be solely the decision of the caller whether to wait or not. There can only be waiting messages on one side of the communication channel otherwise you risk deadlock. The whole system has to be designed with the possibility of waiting messages in mind -- it isn't a decision that any single actor can make on its own. Moreover, the goal of the AF is to discourage nearly to the point of waving off completely the use of waiting messages. Designing a system to wait for a *specific* reply and designing a system to wait for *the next message and then do something special when that message happens to be the reply* is different, but is not a significant design challenge. That was the open question -- the second biggest open question -- at the start of the AF project, but at this point, three years later, we've had enough systems built and done enough theoretical work that I can say with fair certainty that Reply Msg should be avoided and when it is used, it has ramifications on the system as a whole, and therefore no single actor should be able to decide it will wait for a given reply on its own.