I'm developing an API for several customers. All customers get the same methods, but the prototypes and implementations might be different. I have a method loader that looks like this:
The method loader dispatches the customer-specific prototype based on the customer's class that I load from configuration. While there's nothing wrong with this loader, I'd really like to get away from "one state per method" because I have hundreds of methods to expose. I have a standard name prefix for all command prototypes and implementations, so I'd like to load them from disk. I'd like to avoid one class per method. I'd like something like this:
Which appears to be unsupported in LabVIEW 2015. Does anyone know of a supported way to skin this cat?
Thanks for taking a look,
Solved! Go to Solution.
I think the terms "dynamic dispatch" and "automagical" are misplaced here.
If the developer choses a correct OOD, the OOP implementation of dynamic dispatch already solves everything you want to except one: Connector panes must be identical (except calls input/outpu) for all VIs in on "dynamic dispatch tree".
That being said, the issue to solve is to get a generic connector pane (parameters.... i assume that this is what the OP calls "prototype"). The only solution is using flexible datatypes as LV OOP doesn't allow overloading and polymorphism for dynamic dispatching. There are two datatypes usable for this:
Both have their advantages and disadvantages each, so please investigate which one is more suitable for your requirements.
EDIT: Automagical reminds me of unicorns.... anyone else having that weird association?
Thanks for taking a look. I appreciate your time and questions.
The generic problem I'm trying to solve is, "how do I run dynamic dispatch VIs from disk?"
"...but it isn't loading anything..."
IMHO, who knows what it's doing? It might be shining shoes. Calling it a method loader was too specific out of context, I'm sorry. My framework ingests references and spits out an API. I called it a method loader exactly because my references are "...accumulated into an array." This array then defines my methods for my customer. ...Yea, that was confusing for sure!
On that note, "...the issue to solve is to get a generic connector pane..." is not my issue. I have identical connector panes, the output type is strict, native, and what's required downstream.
"The bottom code has a broken wire because you don't have anything wired to the open to define the connector pane."
I browsed to the prototype of this VI. I wired the class into the dynamic dispatch terminal. It's broken because, to use NI's words, "The Call By Reference node does not support dynamic member VIs in this version of LabVIEW" (2015).
"...it still might not work if the input to the VI being called is a dynamic dispatch VI."
Agreed, that's the problem I'm trying to solve. I want to load a dynamic dispatch VI from disk and run it, while retaining the benefits of LVOOP, because I might want to override one of these.
you are familiar with LVOOP based plugin architectures using "Get LV Class Default Value.vi"?
If not, this is what you are looking for....
PS: Nice unicorn
Way, way, (way) upstream we use a similar technique to load the class for Customer X. That part works.
Now, (and again, my work-around is OK), each customer's class has the same method names <standard prefix + method name>.vi, but different implementations. I want to grind through all <standard prefix + method name>.vis, let LVOOP dispatch whatever VI is (or is not, i.e. run the parent) defined for Customer X, and do so without hard-coding each VI in a sequential state machine.
The VI server approach would be exactly what I want; but if I make the class terminal static then I can't dynamically dispatch Customer X.
Thanks for sticking with me.
I'm not sure if i understand what you are saying.... however, this is the approach that works:
Key is INHERITANCE of LV classes....
EDIT: In case you are wondering: The class functions are from the parent class... however, during runtime, child classes are loaded and the dynamic dispatch overrides will execute. If no override for that specific child class exists, the parent method will execute.
In that picture, imagine that instead of INIT.vi, all plugins could have the following dynamic dispatch VIs:
That's basically what I'm working with. In LabVIEW, I have to put INIT_001.vi through INIT_300.vi on the BD if I want to override them. That's exactly what I'm doing with my "method loader", but it feels silly. I'd rather load the collection of INITs from disk, based on their file name, and dispatch them automagically. I feel like we're getting close to sharing understanding. IMO, it's OK if the answer is:
[...]I feel like we're getting close to sharing understanding. [...]
Of that, i am not convinced...
I think you are talking about 300 classes. One class with 300 different inits is pure misdesign and should be scrapped immediatly.
Handling 300 child classes can be challenging, but it is doable. Having 300 different inits per class is not doable.
I appreciate your enthusiasm. I agree that there should be "an" initialization VI per plugin. However, this is not an initialization VI. I was using the picture you posted (arrow pointed to INIT) to clarify what I'm after. Let's bring the specific context of my question back into consideration.
My "INIT" VIs are actually Cmd_def_<command_name>.vis. Each Cmd_def VI exports a method to my customer. I'm exporting a few hundred methods. This is a tool. In my original post I wrote, "I'd like to avoid one class per method." One class per method is too much time and overhead compared to "adding a state to a sequential state machine."
In your opinion, is one class with 300 methods not doable?