LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Organizing class inheritance combinations

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.

0 Kudos
Message 51 of 65
(1,358 Views)

@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.

Message 52 of 65
(1,347 Views)

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.

0 Kudos
Message 53 of 65
(1,335 Views)

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.)

0 Kudos
Message 54 of 65
(1,326 Views)

@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.

0 Kudos
Message 55 of 65
(1,310 Views)

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.

0 Kudos
Message 56 of 65
(1,292 Views)

@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.

0 Kudos
Message 57 of 65
(1,271 Views)

Intaris wrote

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.


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).

0 Kudos
Message 58 of 65
(1,269 Views)

@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.

0 Kudos
Message 59 of 65
(1,267 Views)

@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"

0 Kudos
Message 60 of 65
(1,259 Views)