Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Actor Framework + Interfaces: Why does calling an interface method hit the prototype instead of the implementation?

Solved!
Go to solution


Hi all,

 

I’m trying use Actor Framework with Interfaces and I’m confused about how to correctly use an interface to communicate between actors.

I order to understand it, I made a basic project setup as this;
Server Actor: top-level actor, it launches other actors.
Producer Actor: Generates data and sends it to the Consumer Actor
Consumer Actor: Receives data and process it.
Interface Actor: used for communication between Producer and Consumer Actors.

 

I know that one way of communication between Producer and Consumer Actors is send message from Producer Actor to Caller (Server Actor) by creating an Interface and Server Actor inheriting their methods and it passes to the Consumer Actor, since Server Actor has all the Nested Actor enqueuers. (As I understood from Tom McQuillan's YouTube series on AF)

 

Or alternatively I can send (share) each actors enqueuers to each other and access their actor methods and messages directly.

 

My question is if I can communicate between Producer and Consumer Actors directly. If they share their enqueuers to other actors, then I believe it is against AF (OOP) methods. I only want to access inherited and implemented methods.

I tried to this using "To More Specific Class" wiring target class to Interface and reference (input) as Consumer Actor (which inherits from Interface) and expecting that "specific class reference" (out) gives me a way to use implemented method. But instead I always end up with prototype method that is created when I create the Interface (not the implemented one).

 

Since I am not very experienced in AF and OOP, I might be heading the wrong direction.

Thanks,

0 Kudos
Message 1 of 11
(261 Views)

a) Can you add a picture of your block diagram? 

b) "Or alternatively I can send (share) each actors enqueuers to each other and access their actor methods and messages directly." Until you are an expert with the Actor Framework, I strongly recommend never sharing an Actor's Enqueuer with any other Actor. You will never get a well behaved application that way. Just never do it. Sharing the Enqueuer is almost purely an efficiency technique for serious performance bottlenecks. It is something to be applied after you have a working program if and only if you need it.

c) Your main question: "My question is if I can communicate between Producer and Consumer Actors directly." I do not know what you mean by directly. Enqueuing messages IS direct communication. Your Producer has the Consumer Enqueuer by virtue of launching the nested Actor. Your Consumer has the Producer's Enqueuer by calling Read Caller Enqueuer.vi. No need to share enqueuers with anyone. 

 

To communicate from Producer to Consumer, you right click on the methods of the Consumer Actor, create a new Message class for that method, and then Producer enqueues that Message. 

To communicate from Consumer back to Producer, you right click on a method of the Interface Actor (which Producer inherits from), create a new Message class for that method, and then Consumer enqueues that Message.

 

-- Aristos Queue 

Message 2 of 11
(251 Views)

I assume by "directly" he means send the Producer messages straight to Consumer rather than through Server.

 

Apologies for long post. tl;dr: Don't cross the streams; never share enqueuers across the tree, and don't add backchannel methods to do that either (like a sneaky User Event or something).

 

Long version:

 

I agree this is a bad idea. It seems like it'll save some time now- and it will- because you're sending message from P straight to C instead of P to S to C, but you WILL pay for it later. So, take the time to write the boring boilerplate code that S uses when it gets a message from P.

 

I'd also suggest two things to consider.

 

First is to reframe the way you're thinking about your system. I don't know what data you're acquiring, but clearly you have some way to "get data" and some way to "handle data". So for now I'll call this "raw data" and "processed data". Try to mentally reframe your layout as "My server needs some raw data, so it gets it from Producer. Once it has that raw data, it sends it to Consumer to use that data." Try to consider that each "message hop" is "doing" something different, and it starts to feel less like arbitrarily following the rules, and more about "ah, each item does ONE thing".

 

Say your Producer reads voltage from a multimeter. The Producer ONLY knows "hey I got some voltages. Here ya go." The Server receives that message and "reinterprets" that as "Hey I got some raw unscaled position sensor measurements- let me send it to the Scaling actor." That reinterpretation is a valuable step that can really help keep things cohesive.

 

The second thing to consider is that you COULD have the Consumer be a dependency injection of the Producer. This is a more tricky method to get your head around, so I wouldn't recommend it as an early project, but it's not hard to actually implement. In this paradigm, the Producer always knows it's going to send data to SOMETHING- so, when Server first launches the Producer, it sends a consumer Actor (NOT an enqueuer- an Actor object itself!) to the Producer. Producer stores this in its private data (this would likely be a generic Interface for "thing that can consume Producer's data"). 

 

Once Producer gets data, instead of sending it up the chain to Server, it sends it straight to Consumer- but note that Consumer is now a child of Producer, not of Server. In this method, Server doesn't get to talk to Consumer, but maybe it doesn't have to.

 

Another example- say you're taking pictures from a camera and sending them to a database. Server doesn't need to actually talk to the database, so maybe it could just send the Database Actor* to the Producer. Once Producer takes a new image, it sends it straight to the Database Actor, who puts it into a database. Perhaps it ALSO sends the picture to Server, who displays it on a front panel- but those are two different functionalities, even though the payload of a given message is the same in either case.

 

*This is a contrived example, because in reality you might need some sort of status info on the database to show up in Server, in which case you'd want Database to be a child of Server, not of Producer. And there's also the discussion of whether or not something that interacts with a database should be an Actor, rather than a regular vanilla Object, since simply writing to a database doesn't require an async message loop. But this post is long enough already.

Message 3 of 11
(221 Views)

I didn’t get a chance to read it all so this might be redundant, but Tom’s series on AF doesn’t cover interface messaging. If you haven’t otherwise seen his follow up video on interface messaging, I recommend this:

https://youtu.be/oYUow2c-nCE?si=wrl9qmgXC3AzzHZE
Apologies if this has already been stated.

Message 4 of 11
(215 Views)

I'll focus solely on the following as AQ, Bert and Nathan have addressed your query otherwise.

 


@mhrrm05 wrote:

...how to correctly use an interface to communicate between actors.

Interfaces are used to loosen coupling. A typical scenario would be a LabVIEW application that must concurrently support variations in deployment based on either the actual components used, or the client interfaces needed, or slightly differing business logic even.

  1. When an Actor needs a Nested Actor with specific behavior characteristics, but otherwise doesn't care about the exact class of the Nested Actor itself. (What Bert was partly alluding to.). Best for when your core product messaging is to be preserved, while accommodating the deployment variations as stated above.
  2. When a Nested Actor sends its events to its Caller and must not have any knowledge of the Caller's class. (Nathan's link to Tom's video.) Best for reusable Nested Actors...

AQ's message is particularly pertinent, if you are starting out with AF and are designing a single-line product/application. You wouldn't even need Interfaces then.

0 Kudos
Message 5 of 11
(179 Views)

Hello Aristos,

Here is the block diagram of what I was trying to do. I was trying to get access to only the implemented method of Consumer Actor, but when running I only get prototype method of Interface (Int_DataTransfer). I do not launch the Consumer Actor from Producer. Instead I have Server Actor that launches every other Actors. 

 

Ultimately, when I start to write my program, I will have multiple devices (multiple Actors) that stream data, I will acquire and process data (Acquisition Actor), user interface (UI Actor) and logging Actor etc. So instead of sending data through a Caller Server Actor, I was thinking to send data directly to relevant actor using Interfaces if I have a reference to that target Actors implemented reference. (I only wanted to access implemented Interface methods.)

 

 

Launch Consumer Actor.png

0 Kudos
Message 6 of 11
(160 Views)

Hi BertMcMahan,

Thank you for the very informative message.

What you describe is exactly what I tried to do. Only that instead of sharing my Consumer Actor to my Producer Actor (because Producer Actor might not need or should not access all the methods of Consumer Actor), I thought I can create an Interface, Consumer Actor implement its methods and Producer Actor have only access to those methods, hence also bypass the Producer-Server-Consumer communication.

I have a position sensor that I can write/read through serial port. I will be constantly reading data and put in on my UI and process and log the data whenever I needed to (either by a pushbutton on UI or trigger event etc.) And I will have other sensors to add to later. Since I will read data constantly, I thought get rid of the middle man (Server Actor) and send the data directly from  Producer to Consumer. I even thought of using a DVR and share the DVR Ref. to consumer but I didn't know if was a proper thing to do in AF design.

 

But I think it is better I will stick with what you and AristosQueue suggest and keeps thing at basic level until I get more experience on AF.

0 Kudos
Message 7 of 11
(152 Views)

@mhrrm05 wrote:

Here is the block diagram of what I was trying to do. I was trying to get access to only the implemented method of Consumer Actor, but when running I only get prototype method of Interface (Int_DataTransfer). I do not launch the Consumer Actor from Producer. Instead I have Server Actor that launches every other Actors. 

 

Launch Consumer Actor.png


The 'To More Specific Class' primitive is incorrectly used. Your code is forcing a concrete class wire to the Interface wire, causing the symptoms you see. You should be able to wire the Consumer class directly to the upper element of your Bundle-By-Name.

Are you trying to access the Consumer class's methods both, directly and via actor message? Both approaches can co-exist, as long as you have valid justifications for them.

 

0 Kudos
Message 8 of 11
(148 Views)
Solution
Accepted by topic author mhrrm05

@Dhakkan wrote:

The 'To More Specific Class' primitive is incorrectly used. ... You should be able to wire the Consumer class directly to the upper element of your Bundle-By-Name.

 


Even though the To More Specific Class is unnecessary here, the code should work. ... Unless... unless Consumer does not actually inherit from Init_DataTransfer? Do you get a broken wire when you connect Consumer directly to the Bundle By Name node? If so, check that your inheritance is implemented. That would be one explanation for why you are later getting the interface implementation. 

 

@mhrrm05, in general, if you *ever* fork the wire that goes into a Launch Nested Actor node, you're doing something very wrong. The data value coming out of the Consumer constant is forked to both the Launch Nested Actor node and to the Bundle By Name node. When I see that fork, coupled with the fact that you say you're new to the framework, I strongly suspect that you're a C# or Java programmer, or similar language background. And when I see that you named the field "reference", I *know* that's your background. Why? Because that's false. 🙂

 

In LabVIEW, that wire fork creates a full data copy (pass by value in C++), not a reference. Objects in LabVIEW pass by value always. The changes that happen to the copy of Consumer that gets launched will NOT be shared by the copy of Consumer that is placed into the Bundle By Name. There are nearly zero cases where what you have written is correct code. Somewhere downstream of this code, I suspect that you are Unbundling the "Init_DataTransfer class Consumer reference" field and expecting that to be the value of your launched actor. It will not be. The ONLY way to communicate with your nested actor is by sending a message and then getting a reply. That is intentionally the only way.

 

Abandon all thought of references. Pretend that wire is an integer while you're designing your code. How do integers behave? That's the same mindset you should use for all objects in LabVIEW. 

 

🙂 

-- Aristos Queue

(inventor of the Actor Framework and former language architect for LabVIEW)

0 Kudos
Message 9 of 11
(137 Views)

Hi,
I don't get a broken wire when I connect the Consumer Actor to the Bundle By Name node.

 

No, although I had C classes before, I am not a software engineer or programmer, That is why I like LabVIEW for non-engineers and the way it is a graphical programming. I always used LabVIEW with State Machine, Producer/Consumer or QMH, and OOP was always difficult to comprehend for me., until when I get time to study AF.

 

Lately I tried asking questions to the so called AIs and from one of many answers this was one of the things that I thought it would work. My mistake!

 

"Somewhere downstream of this code, I suspect that you are Unbundling the "Init_DataTransfer class Consumer reference" field and expecting that to be the value of your launched actor. It will not be."

Yes I thought it would be. Thanks for clearing that.

 

This topic actually not only answered my questions, but also made me understand more on AF.

Thank you,

0 Kudos
Message 10 of 11
(120 Views)