08-30-2024 04:18 AM
Hi all,
I'm designing an AF based application where actors are built into PPL. But I'm not sure how to handle Interfaces.
Usually (when I develop small AF app, without PPL), I create a second lvlib containing the actor interface. In the nested actor, I use "Send Msgs" from my interface. And my caller inherits from the interface.
But with PPL, I'll need to first create my interface, build it into PPL and then call it in the nested actor, am I right? That's more to handle.
Why not having a top lvlib containing both the nested actor and it's interface lvlibs? I get only 1 PPL for 1 actor. The only downside I can think of is in case I want multiple actors to share the same interface. But if I don't, is it ok to do so?
08-30-2024 04:26 AM
It always depends.... if you're SURE you are not reusing the interface again... yet what's the point in having an interface used just by a single actor?
For inspiration, I highly recommend Allens presentation at GDevConNA https://youtu.be/ngx_nh0wBGQ?feature=shared
08-30-2024 06:11 AM
The goal is to be able to re-use the nested actor in other applications. If I don't use an interface, it'll have a dependency to the calling actor, preventing reusability.
I'll watch the presentation right now, it's on point!
09-01-2024 07:29 PM
I stopped using PPLs, but agree the only downside to your proposal is not sharing interfaces for multiple actors. I don't think I've ever reused an interface in that way, but maybe you have.
I like to make my actors like this. It makes it easy to see what's going on, and to scope private messages.
I like this because it namespaces nicely (Something Useful.lvlib:Actor.lvclass), and it's much easier to rename the actor. The whole thing should package nicely into a PPL.
Speaking of namespaces, watch out for the Caller interface methods... probably need to prefix each VI with the interface name to avoid collisions (for example if many Callers have a "Configure" message with different I/O).
Good luck with the PPLs...
09-04-2024 09:59 AM
Me neither, Ive never reused an interface. But if the case happens I guess I'll separate it from the actor.
I like your architecture, it's simpler that way.
09-04-2024 02:06 PM - edited 09-04-2024 02:09 PM
@Oli_Wachno wrote:
It always depends.... if you're SURE you are not reusing the interface again... yet what's the point in having an interface used just by a single actor?
This.
Edit to add: I do take your point about decoupling. I often have interfaces *just* to decouple actors. But I'd have them in separate PPLs. Interfaces are foundational software elements.
09-04-2024 02:14 PM
@OneOfTheDans wrote:
I like to make my actors like this. It makes it easy to see what's going on, and to scope private messages.
- Something Useful.lvlib
- Actor Messages
- <all Actor messages in here>
- Caller Messages
- <all Caller messages in here>
- Actor.lvclass
- Caller.lvclass <an interface that the Caller is expected to implement>
The down side to this is that your Caller *library* is coupled to Something Useful, and is therefore coupled to everything that is called in Actor. If any of that stuff is in a library (like another of your actor libraries), you'll load all of *that* stuff. You can build some pretty long coupling chains that way.
09-04-2024 02:36 PM
Not sure I follow the issue with chained coupling. Do you agree it's standard practice to keep an Actor and its Actor Messages in one library (regardless the naming convention)? Then any Caller Library:Actor is already pulling in the whole Something Useful library, Actor, and dependencies. What additional coupling is added by including Caller Interface.lvclass in the same Something Useful library?
To your other point - do you have a practical example where multiple actors use the same interface? The closest I've come to that has always been naturally solved with inheritance, like a Base Module:Actor (with it's Caller Interface & messages) plus subclasses for My Module.lvclass. The best case I've seen for this was a fellow recently asking about 1 interface for every single message, so Actors could mix/match what they transmit and subscribe. I think this was for GUI work, in particular.
09-04-2024 02:41 PM
I think (could be wrong) the suggestion is if you split like this:
Interface.lvlibp
- Interface
- Public messages for interface methods
Concrete.lvlibp
- AwesomeActor
- implementation of the interface
- Private messages as needed
then caller only requires the interface, and the app requires both but could conceivably load Concrete at runtime (if you wanted that).
An example of coupling more stuff here is if Concrete's AwesomeActor also calls stuff from DatabaseLogging.lvlibp, or FileWriter.lvlibp, etc (because the interface may not care about these things).
09-04-2024 03:06 PM
@cbutcher wrote:
Interface.lvlibp
- Interface
- Public messages for interface methods
Concrete.lvlibp
- AwesomeActor
- implementation of the interface
- Private messages as needed
We might be talking about different things? I think you're describing that AwesomeActor implements the Interface, thus decoupling messages sent down the tree (caller-to-nested). What I meant to suggest is an interface for the return data sent up the tree (nested-to-caller). I'll try to redo the tree for clarity...
For dynamic loading and whatnot, Useful.lvlib would be an abstract actor, from which concrete actors inherit.