Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Need a more detailed explanation of "Zero Coupling" in Messages

Solved!
Go to solution

I've read this block of text from the whitepaper about six times, and it still makes no sense to me:

The Zero Coupling Solution — In order to make the callee actor independent from the caller, the caller must tell the callee what types of messages to send so the callee avoids picking a type itself. The best implementation of this solution has the caller record a message into the callee at the time the callee is launched. The callee provides a Set <Type> Message.vi method, where <Type> is the particular event that will trigger the message to be sent. The caller  sets the exact message it wants to receive when this event occurs. When the event happens, the callee sends the chosen message, without any knowledge of what kind of caller is receiving that message.

What "event" are you talking about? Is it a LV event that you dynamically register? Can you give an example implementation, either as a screenshot or as source code?

Often the callee will define an abstract Message class that it uses as the input type for Set <Type> Message.vi. Callers create their own specific child of this abstract class. This setup gives the callee a way to set data into the message through the API defined by the abstract class, and gives the caller a way to deliver that data in a form the caller can consume through the various overload and extension VIs.

You're just describing a Factory Method for defining message types to be sent by a particular object, right? That's what I've been doing: any message sent by a loosely-coupled actor is abstract, and I use a constructor method to initialize the actor with the concrete types of those messages. Actors always use concrete-typed methods with received messages.

0 Kudos
Message 1 of 17
(20,833 Views)

Event in the sense of "thing that happens in your application that makes you want to send this message." So, if you're building an Engine actor that occassionally needs to report its temperature, you might have a "Set Report Engine Temperature Message.vi" and a "Report Engine Temperature Msg.lvclass" that is the abstract message class. That engine might be used by a Truck or by a Car. Each of those classes would have a concrete message class named something like "Report Engine Temp To Truck Msg.lvclass" and "Report Engine Temp To Car Msg.lvclass".

DavidStaab wrote:

You're just describing a Factory Method for defining message types to be sent by a particular object, right?

No. The caller knows exactly which type of child class to pass in and passes in that explicit object to the "set message" VI. There's no factory involved.

Message 2 of 17
(7,470 Views)

Zero coupling is a myth.  The only two processes which have zero coupling are two processes which have absolutely nothing to do with each other.  Like what I want and what my wife wants.

I don't like the term "Zero" coupling, I much prefer "Low" coupling because a certain miniscule amount of coupling is neccessary always.

The lowest coupling I could imagine in this context would be the callee sending only messages of the base class back to the caller.

Shane.

0 Kudos
Message 3 of 17
(7,470 Views)

AristosQueue wrote:

Event in the sense of "thing that happens in your application that makes you want to send this message." So, if you're building an Engine actor that occassionally needs to report its temperature, you might have a "Set Report Engine Temperature Message.vi" and a "Report Engine Temperature Msg.lvclass" that is the abstract message class. That engine might be used by a Truck or by a Car. Each of those classes would have a concrete message class named something like "Report Engine Temp To Truck Msg.lvclass" and "Report Engine Temp To Car Msg.lvclass".

I think that section needs some heavy rewriting and a descriptive screenshot. I would remove the references to an "event" and just talk about sending a message, regardless of what motivates an actor to send it.

AristosQueue wrote:


No. The caller knows exactly which type of child class to pass in and passes in that explicit object to the "set message" VI. There's no factory involved.

Ah, right. I guess the FM pattern is subtlely different. What I described in my code is exactly what I'm doing: the caller (class that <<uses>> the receiving actor, in a class diagram) holds a set of concrete messages it wants to hear and passes that set into the receiving actor upon launch.

0 Kudos
Message 4 of 17
(7,470 Views)
Solution
Accepted by topic author David_Staab

Stephen beat me to it.  I would add that zero coupling is implemented with a strategy pattern.

To elaborate on his example, you would create "Report Engine Temperature Msg.lvclass", which has engine temperature data and a Send Msg method, but no Do method.  (The Do method has to call a method of the recipient, which is what we need to avoid.)  The Send Msg method is dynamic dispatch, and takes a Report Engine Temperature Msg object as an input.  Engine (the Actor) carries a Report Engine Temperature Msg in its attributes, and provides an accessor to set the actual child type (Report Engine Temp to Truck Msg, for example).

The actor that calls Engine (Truck, for example), will provide a message for itself called Report Engine Temp to Truck Msg, which is a child of Report Engine Temperature Msg.  This new message has no data, and no Send method, but provides the Do method that calls the correct method of Truck.  When Truck creates Engine, it gives an instance of this message to Engine by way of the accessor.

When Engine needs to report its temperture, it will get the actual message instance (Report Engine Temp to Truck Msg) from its attributes, and send that message.

In this way, Engine defines the type of data it will send, but Truck defines the method that will be called when it receives that message.

You can see an example of this in the shipping example, in the relationship between Cooler and Dual Fan.  Dual Fan provides an abstract message to be sent to its caller; Cooler defines a concrete child.

The hands-on included creation of a zero-coupling relationship, but I had to cut it for time.  I will take that material and rework it as a stand-alone exercise, and publish it at some point.  The concept is a little tricky to explain, but simple once you've done it a time or to.

Message 5 of 17
(7,470 Views)

So, in short, to achieve Lower Coupling (in conjunction with Intaris's concern about nomenclature):

  • Send abstract messages.
  • Receive concrete messages.

Got it.

Message 6 of 17
(7,470 Views)

Thanks niACS. David you can see an example in the "Fan Cooler", but it's so difficult see if you don't know where to search (look Feedback Cooler - Actor Core.vi), after think a lot how implemented this I guess i have an answer(for me at least):

Really is Engine who defines how is this message "Report Engine Temperature Msg.lvclass", and what kind of data would send to his caller, because only Engine know what kind of data send. Then, if Truck want to use the Engine Actor must to implement a child message of "Report Engine Temperature Msg.lvclass", with his Do method for work with the data that Engine send

is this correct?

0 Kudos
Message 7 of 17
(7,470 Views)

Intaris wrote:

Zero coupling is a myth. 

No, it isn't. The callee does not know the type of its caller. The caller could be swapped out for an entirely different module and the callee would still funciton. Contrast with couplings that the callee breaks if the caller is replaced. Do they talk through an interface? Yes. But it is an interface defined by the *callee*, not one dictated by the caller to which the callee conforms.

0 Kudos
Message 8 of 17
(7,470 Views)

AristosQueue wrote:

Intaris wrote:

Zero coupling is a myth. 

No, it isn't.

I mostly agree with Intaris, though I'd change it to "Zero coupling between any two collaborating components is a myth."  Obviously the validity of the claim depends on how one defines "coupling."  I prefer this definition as stated by Martin Fowler:

"If changing one module in a program requires changing another module, then coupling exists."

I prefer to think of it in terms of decoupling, so I use the corollary:

"For any two components, if I can make an arbitrary change in either one without requiring a change in the other, the two components are zero coupled."

AristosQueue wrote:
The callee does not know the type of its caller. The caller could be swapped out for an entirely different module and the callee would still funciton.

I agree with this statement; however, I disagree with the conclusion.  The ability to swap out the caller and have the subactor (callee) still function correctly is not sufficient to claim the two components are "zero coupled."  Swapping the caller is possible because the subactor is not statically dependent on the caller.  While static dependencies do create coupling, it doesn't follow that no static dependencies means coupling does not exist.  To simplify the logical error:

Premise 1: If A, then B.

Premise 2: Not A.

Conclusion: Therefore, not B.

Clearly the argument is logically invalid.  There are lots of ways to couple two components together.  Static dependencies are one form of coupling. It happens to be a fairly tight form of coupling, is very commonly used among LV programmers, and is usually the first kind of coupling developers learn how to break.  For these reasons I think it is natural for people to equate static dependencies with coupling, but coupling covers a much broader scope than static dependencies.

Furthermore, stating two components are zero coupled implies neither is coupled to the other.  In the example given in the paper, at best you can say zero coupling exists in one direction--the subactor is completely decoupled from the caller--but even that is open to discussion.  It is obvious the caller remains coupled to the subactor.

The technique described in the zero coupling solution is completely appropriate and the correct way to build a subactor that is not statically dependent on the caller.  Calling it a "zero coupling solution" is, imo, incorrect and confusing for people trying to learn the concepts.

Message 9 of 17
(7,470 Views)

AristosQueue wrote:

No, it isn't. The callee does not know the type of its caller. The caller could be swapped out for an entirely different module and the callee would still funciton. Contrast with couplings that the callee breaks if the caller is replaced. Do they talk through an interface? Yes. But it is an interface defined by the *callee*, not one dictated by the caller to which the callee conforms.

Well let's just agree to disagree.

No two modules can communicate in any way without having some common ground on which to exchange messages.  While this is practically the lowest coupling one can achieve it is still dependent on the implementation of the messaging and is thus NOT zero coupling.  But I fear we are using two different definitions of coupling.  For me the interface is part of coupling, for others it's not.  Other users mileage may vary.

The reason why I'm pedantic about this is that when trying to learn OOP, its written often that reducing coupling is very good and one can make oneself crazy trying to implement a "zero" coupling solution which, for me at least, is not practical.  It's neccessara to distinguish between neccessary coupling (as in some degree of functionality) and zero coupling (Which be my definition eliminates all common ground for two modules to communicate to each other beacuse a change in the messaging from one side WILL affect the functionality of the other.

While I agree wholeheartily that in general reducing coupling is something to be strived for, the search for a "zero coupling" solution almost always ends in tears and windmills (Ben will know what I'm referring to).

The message that there is a differentiation between neccessary coupling and unneccessary coupling is a VERY important one, especially for OOP newcomers.

Shane.

Message 10 of 17
(7,470 Views)