08-15-2012 10:22 AM
Dmitry: I understand how your architecture works. My point in asking the question about scope was an exploration of other options for modifying the already-released Actor Framework to achieve the same goals -- i.e., making it so that a nested actor can send only messages that are intended to come up the tree and not able to send any messages that are intended to come only down the tree. Splitting out the interface as you describe is not going to be possible to retrofit at this date without breaking existing code unless we are able to apply some sort of version mutation. I doubt our ability to come up with a mechanical way to take someone's existing application and mechanically transform it to separate the communications layer from the API interface. Thus I was exploring access scope definitions as a different way to define what messages go up vs what messages go down.
For example, it occurs to me that we could also solve this problem by splitting the Message hierarchy into two types of messages: Up-Tree Messages and Down-Tree Messages. We would have two different types of Enqueuers: one that accepts Up-Tree Messages only (for actor sending to its caller) and one that accepts Down-Tree Messages only (for actor sending to its nested actors). All the messages would end up in the same actual queue on the back end. But, of course, you still have the problem that a nested actor could define an Up-Tree Message to call any item in public scope. So, could we either use the existing scopes (public/private/protected/community) in a creative way to prevent the nested actors from creating messages to methods that are meant to only be called from above OR could we introduce a new scope into LabVIEW.exe to help define this situation better, without introducing the interface classes? The former is obviously easier as it requires G changes and the community could produce a new AF to support the separation. The latter would require changes to the LV language definition and would push such work out to 2014 at least (2013 being already well along in development and developers fully loaded).
So here's my idea:
Would the overall scheme satisfy your goals? If so, can you think of a way to fix step 6 to be automutatable?
08-15-2012 10:24 AM
Alternatively, we just leave Stop as a public method, introduce both a UTM version and a DTM version of it and document it as a special case.
08-15-2012 02:59 PM
AristosQueue wrote:
So here's my idea:...
IMHO you're both firing up rockets to go to space. While this problem of callee-controlling-unknown-caller can indeed occur in the existing AF, it's avoided by any good OO programmer who follows the dependency inversion principle. Anybody trying to use AF without a strong basis of experience in LVOOP should probably rethink their decision.
Instead of making the framework still more complicated and the learning curve still more like a sheer cliff, I recommend just documenting this possibility along with other "ways to shoot yourself in the foot" (like poor error handling overrides, failing to stop your AC.vi override, putting infinite blocking calls in a message method, etc.) in the whitepaper or another NI Community document.
08-15-2012 03:09 PM
In general, I think you and I agree, David... Leave it alone unless we find an elegant way to prevent it entirely. There's always a balance to be struck between documenting "don't do this" and building a wall so you can't do that. Dmitry's original suggestion would ramp the complexity, but the goal is right, now that I understand what he is aiming for. What I am laying out are options for creating that separation and see if any of them really shine -- basically, are any of the walls cheap enough to be cheaper than both the learning curve and the debugging headache when someone (deliberately or accidentally) "does that". 🙂
08-15-2012 03:11 PM
Gotcha. I had the impression you were already writing the feature spec for 2013.
08-15-2012 03:12 PM
AristosQueue wrote:
Dmitry: I understand how your architecture works. My point in asking the question about scope was an exploration of other options for modifying the already-released Actor Framework to achieve the same goals -- i.e., making it so that a nested actor can send only messages that are intended to come up the tree and not able to send any messages that are intended to come only down the tree. Splitting out the interface as you describe is not going to be possible to retrofit at this date without breaking existing code unless we are able to apply some sort of version mutation. I doubt our ability to come up with a mechanical way to take someone's existing application and mechanically transform it to separate the communications layer from the API interface. Thus I was exploring access scope definitions as a different way to define what messages go up vs what messages go down.
.....1. Introduce two new children of Message -- Up-Tree Message and Down-Tree Message (here after abbreviated UTM and DTM).
....
6. This would not break any existing code except for nested actors that are sending Stop to the callers. It would be obvious to a developer what needed to be fixed, but I don't have a suggestion for any way to automate creating a custom UTM to send the Stop because we wouldn't know the actor class intended to receive the message.
Would the overall scheme satisfy your goals? If so, can you think of a way to fix step 6 to be automutatable?
Well, it seems that we don't have too much 'wiggle room' here... My gut feeling is that above solution adds unnecessary complexity and would confuse AF developers. What may be done instead (at this point) is to educate them:
The latter can be done by "The Caller" registering a LastAck with nested actors (I think James favors this approach). Or not registering it at all if an application does not use it. I would use a basic Topic pub/sub (see my post #13) as Topic pub/sub scales well when you move from strict hierarchies to graph-like topologies ...
08-15-2012 04:52 PM
AristosQueue wrote:
Ok. I see where you're coming from. Your objection makes sense.
Now, where were you eight months ago? 🙂
Eight months ago I was sitting on a open deck with a 180 degree Ocean / Kealakekua Bay view in Captain Cook, Big Island, Hawaii. Snorkeling two best spots of the Big Island, kayaking in Kealakekua Bay, making Turkish coffee out of hand-picked Kona beans growing on the property, walking on brand-new lava fields and driving from sea level to Mauna Kea summit (13,700 feet) in 2.5 hours . I definitely wasn't concerned with AF or ArT_Actors during those 15 days ...
And you have to introduce an interface class for every pair of actor classes. And you have to downcast the interface object received to the particular interface being used, putting a lot more weight on the developer of the callee actor. Not saying its impossible, but it ain't helping the ease-of-comprehension of the system.
Well, in ArT_Actors most of this stuff should be handled by the API Generation Tool. And in most cases (excluding Blocking and Asynchronous Request modes) developer does not have to even create a message - it's all handled by the API code. So instead of 20 Message classes I have to deal with 20 methods within an API class. With good design practices APIs are highly reusable. Each API is generated from its Actor Class (one API method per Actor method), etc. And instead of a flat set of Message Classes I get a nice Message Class Hierarchy enforced by Actor APIs ... Sounds like a Structured Messaging concept to me . Don't know yet if it will be as good as Structured Data Flow
- the proof of the pudding is in the eating, after all ...
What if we were to start annotating the Message Enqueuer class (formerly the Send Queue class)? Suppose when Actor A launches Actor B, it provided a list of class types as an input to Launch Actor.vi, and that list could be stored into the Message Enqueuer that is given to Actor B. Every time a message gets sent, its type could be checked against the list of approved types and rejected if it isn't on the list. That's a run time guard instead of the compile time guard.
Are there other approaches that give you the division you're seeking?
Now, that I have a much better understanding of AF3.0, I plan on reviewing what/how needs to be changed in ArT_Actors and/or AF4 to have ArT_Actors as a proper extension of AF4. There is a lot of value in being a part of such vibrant community and, besides that, I do not have enough time/bandwidth to create/maintain all the tools developers need to tackle actor-based applications. I will post the outcome here some time next week ...
08-15-2012 06:39 PM
Dmitry wrote:
This junior guy sits in design meetings and is aware of overall design and Scanner internals. And he thinks of a cool way to implement a Shutter function - which requires sending a custom message to Scanner Actor - implements that message (based on intimate knowledge of Scanner plumbing) and everything is honky dory ... Well, next month, another team try's reusing this Shutter Actor and runs into a problem because they use a different implementation of Scanner Actor for another line of products...
...Another example - that same junior screwed up with Shutter Actor data structures - resulting in Shutter Actor sending a Stop Message to Scanner Actor...
Do I see a good solution? Yes
I do - instead of coupling Shutter Actor to Scanner Actor via Message Transport (Actor-to-Caller Queue), couple them via a Scanner API specifically designed for getting feedback from an Abstract Shutter....
My "good solution" would be to smack the junior engineer and remove his write permissions to the source control tree until he demonstrated the ability to make good coding decisions. Easier, faster, and waaaay more satisfying.
08-15-2012 07:57 PM
Daklu wrote:
My "good solution" would be to smack the junior engineer and remove his write permissions to the source control tree until he demonstrated the ability to make good coding decisions. Easier, faster, and waaaay more satisfying.
Sure, it may be recommended as a best practice in a number of countries, but here, in the US, it would qualify as an aggravated assault
08-15-2012 08:06 PM
Then make him buy breakfast every day until he fixes the build.