06-10-2013 04:24 PM
Oh, maybe the miscommunication is about arrays. It's not a requirement that we be able to iterate through an array of different devices; I probably shouldn't have mentioned that at all as it seems to have confused things.
There are cases where I've buffered readings in superclass private data that could then be accessed in iteration over the array of the superclass, but it sounds like solutions here wouldn't preclude doing that anyway.
06-10-2013 05:40 PM
@crcarlin wrote:
Oh, maybe the miscommunication is about arrays. It's not a requirement that we be able to iterate through an array of different devices; I probably shouldn't have mentioned that at all as it seems to have confused things.
Ok. Without that requirement, then, yes, I would point you to a combo of dynamic dispatch and polyVIs.
You have a set of device classes. Some have inheritance, some do not. There is not a common root ancestor (other than LabVIEW Object).
You add methods to the classes as needed. So if two independent hierarchies need a "Get Temperature.vi", you add it to those hierarchies and override as needed.
You create polyVIs that contain the eldest implementation of each method in each hierarchy.
Example:
You have device Alpha, AlphaChild, Beta and Gamma. AlphaChild derives from Alpha.
You create the following classes and methods:
Alpha.lvclass
DoMeasurementW.vi
DoMeasurementX.vi
DoMeasurementY.vi
AlphaChild.lvclass
DoMeasurementY.vi (override)
DoMeasurementZ.vi
Beta.lvclass
DoMeasurementY.vi (not an override)
DoMeasurementZ.vi (not an override)
Gamma.lvclass
DoMeasurementW.vi
DoMeasurementQ.vi
You create 5 polyVIs containing the instance VIs listed here:
DoMeasurementW.vi
Alpha.lvclass:DoMeasurementW.vi
Gamma.lvclass:DoMeasurementW.vi
DoMeasurementX.vi
Alpha.lvclass:DoMeasurementX.vi
DoMeasurementY.vi
Alpha.lvclass:DoMeasurementY.vi
Beta.lvclass:DoMeasurementY.vi
DoMeasurementZ.vi
Beta.lvclass:DoMeasurementZ.vi
DoMeasurementQ.vi
Gamma.lvclass:DoMeasurementQ.vi
Notice that even though AlphaChild.lvclass overrides Y, its implementation is not added to the polyVI for Y. You only need to add the eldest implementation in each tree.
This should give you the behavior you're looking for.
And, yes, this now-with-arrays-removed use case would benefit from interfaces.
06-10-2013 10:04 PM - edited 06-10-2013 10:09 PM
I believe there's one glitch in your diagram: since polymorphic vis can't include dynamic dispatch vis, I don't believe any of the measurement vis can be overriden by any child classes. Every measurement vi has to be manually added to the polymorphic vi.
Also, in my design, which seems to be working so far, the instrument classes all inherit from a common parent class because they all use some methods provided up the inheritance tree, VISA configuration code mainly.
So:
Instrument.class
--GetTemperature.vi (poly)
--GetPressure.vi (poly)
--Various common stuff vis
Device1.class (inherit from instrument.class)
--GetTemperature.Device1.vi (static class added to Instrument.class:GetTemperature.vi
--Overrides for various vis
Device1Child.class (inherit from Device1.class)
--GetTemperature.Dev1Child.vi (static class added to Instrument.class:GetTemperature.vi)
--GetPressure.Dev1Child.vi (static class added to Instrument.class:GetPressure.vi)
and so on.
Sure it's annoying to pollute the namespace, but in my case in particular I rarely need to subclass devices anyway.
06-10-2013 10:37 PM
Ah, right... forgot about that limitation. You can still have inheritance: just create a static dispatch wrapper VI at the top-most level.
(For the record, there's no good reason for the limitation... it just happens that poly VIs have some ancient code that made them resist dynamic dispatch VIs as members and I've gotten very few requests to fix that, so it is has been at the bottom of the priority list, especially since the "static dispatch wrapper VI" workaround exists.)
06-11-2013 02:27 AM - edited 06-11-2013 02:52 AM
@AristosQueue (NI) wrote:
You have a set of device classes. Some have inheritance, some do not. There is not a common root ancestor (other than LabVIEW Object).
You add methods to the classes as needed. So if two independent hierarchies need a "Get Temperature.vi", you add it to those hierarchies and override as needed.
I think I'm missing something here.
If I have an object constant on the BD and have a method "Get Temperature" down the line, what happens if I switch it out with another object which also has a method called "Get Temperature"? I have tried this in the past and was sure the following distinctions could be made:
1) Both objects share a common ancestor with the method "Get Temperature" and the method call on the object wire gets auto-updated. Everything's great.
2) Both objects do NOT share a common ancestor with the method "Get Temperature" and swapping out the object breaks the wire between the object and the "Get Temperature" VI because they are NOT referring to the same method.
Was this observation false? This was a main reason why I was sure the polymorphic route would not work. Perhaps I was mistaken?
Oh hang on. Do you mean to have the poly VI items SPANNING the object trees? So the "Get Temperature" method is actually called by the "Get Temperature" Poly VI which contains the static-dynamic call to the appropriate object tree? Itneresting.
06-11-2013 05:02 AM
It seems (based on this and other posts over the last while) that I'm going all authoritarian at the moment which is not befitting the forums at all.
I apologise if my tone has been out of line in the last time.
06-11-2013 10:00 AM
@Intaris wrote:
It seems (based on this and other posts over the last while) that I'm going all authoritarian at the moment which is not befitting the forums at all.
I apologise if my tone has been out of line in the last time.
Irishman are known to get a wee bit crazy at times.
06-11-2013 10:04 AM
Intaris wroteWas this observation false? This was a main reason why I was sure the polymorphic route would not work. Perhaps I was mistaken?
Oh hang on. Do you mean to have the poly VI items SPANNING the object trees? So the "Get Temperature" method is actually called by the "Get Temperature" Poly VI which contains the static-dynamic call to the appropriate object tree? Itneresting.
Your observation was correct. And yes, I am talking about poly VIs spanning the object trees.
I have often thought about changing the rules for when you change which class is wired to a node to allow it to check the new class for a VI of the same name. I was advised not to do this years ago, but I do not recall the reasoning -- the only thing in my notes is "Had meeting with architects about implicit polymorphism based on method name. Probably bad idea." So that's what got implemented. But I didn't write down the why. It has come up very rarely over the years, but a situation like this one would be simpler in that case -- especially if the conpanes also match (ignoring the class in/class out terminals).
06-11-2013 10:08 AM - edited 06-11-2013 10:08 AM
@AristosQueue (NI) wrote:
Your observation was correct. And yes, I am talking about poly VIs spanning the object trees.
This is blowing my mind. If someone has time, could they draw up a quick example with code? I learn better from pictures; it's why I program in LabVIEW.
06-11-2013 10:20 AM - edited 06-11-2013 10:22 AM
@AristosQueue (NI) wrote:
Your observation was correct. And yes, I am talking about poly VIs spanning the object trees.
I have often thought about changing the rules for when you change which class is wired to a node to allow it to check the new class for a VI of the same name. I was advised not to do this years ago, but I do not recall the reasoning -- the only thing in my notes is "Had meeting with architects about implicit polymorphism based on method name. Probably bad idea." So that's what got implemented. But I didn't write down the why. It has come up very rarely over the years, but a situation like this one would be simpler in that case -- especially if the conpanes also match (ignoring the class in/class out terminals).
If you allowed a class method to "look into" the private data of a connected class which adhered to certain rules (Lets refer to them as "Aggregates" - perhaps a special flag in the owning VI?) to find the correct object to call code on, assuming there was one and only one suitable in order to avoid ambiguity, would we not essentially have a modified form of multiple inheritance?
It would essentially be performed by the compiler if done correctly.
So Instead of "If wire into ClassX:Method is not compatible with Class X Break wire" we would have
"If wire into ClassX:Method is not compatible with Class X, Check if Class X present as Aggregate, if so use Aggregate otherwise break wire"