04-02-2020 07:56 PM
Deuippe!! Watching MICHAEL AIVALIOTIS' little video I see I have it backwards. We load a **specific** child class using 'Get LV Class Default Value', then downcast it to its parent? That seems so backward to me. Michael says "Class data traveling on a generic LabVIEW object wire" goes 'To more specific class'. So we're doing the opposite of what I thought - we're starting with a child class, then downcasting it to its parent?
04-03-2020 06:17 AM
Let me see if I can spell it out
The goal is to write application code where you only lay down parent functions and parent wires on your block diagram. Consequently, when you create your child objects, you have to make them "look like" parent objects.
During initialization, you'll create a specific child object, and then *cast it* to the more generic parent class. Now you'll have a child object that's able to travel along a parent wire. When it arrives at a parent function, Dynamic Dispatch makes sure that what's *actually* executed is the child's own override function.
I found it kinda brain-bending too. It didn't seem intuitive to me that the (parent) function seen on the block diagram is *NOT* the function that's actually executed. But that's how LVOOP works.
The benefits of being able to *extend* functionality by deriving new child classes *depends* on generic-looking parent-level code on the block diagram.
In a HAL, the parent will probably be an abstract class that doesn't implement any functional code in the functions it defines. It exists as a base to inherit from and is the place where the interface to the member functions is defined.
Note: despite the simplified summary I've written so far, watch out for the urge to make an overly generic do-everything parent. For example, consider the case where you need to manage a bunch of instruments that may be connected to a test stand. There could be some kind of DMM, one or more Power Supplies of various types, etc. You might be tempted to make a super-generic Instrument class that abstracts all the possible functionality of all the various instruments. Resist this temptation!
Instead, you should have a generic abstract DMM parent and a separate generic abstract Power Supply parent. The part of your code that deals with DMM-like measurements would lay down generic DMM parent functions. The part that deals with controlling power would lay down generic Power Supply parent functions.
At a certain point it's art more than science and you kinda have to start plunging in to get used to the thought process. The most pure and elegant looking class hierarchy tree will often *NOT* be the most useful and practical one. IMHO. At the end of the day, the code is meant to serve a functional purpose, not win a beauty contest.
-Kevin P
04-03-2020 06:55 AM
Kevin - fantastic explanation, I'm grateful for your help! We quasi-novices are SO lucky to have you experts to help us! I think what I was missing were 1) the concept of 'child data traveling on a parent wire', and 2) the concept of downcasting a specific child class to a more specific parent class. My intuition really struggles against that - I think of a child class as a specific type of its parent class (this is where I get going down the wrong path, I think). The terminology really messes with my head. The Help says
"Typecasts a reference, such as a control or a type definition, to a more specific class in the inheritance hierarchy. For example, if Class A inherits from Class B, a variable of type B can hold a value of type A. You can use the function to downcast from type B to type A. If the typecast is invalid, this function returns an error at run time."
So we give the parent class (Class B) to the function as the "target class is the class to which you want to downcast reference. You can wire a class specifier constant or any wire of the target type to this input." We give the child class to the reference input.
AHAH! Rereading the bit about "... a variable of type B can hold a value of type A". Now I'm starting to get it. Well, I just need to digest and practice. Thanks again for your great help - paul
04-03-2020 08:31 AM
Just to help you keep clear on terminology:
A child is *more specific* than a parent. Always.
A parent is *more generic* than a child. Always.
My impression is that people are more casual in their use of terms like "upcasting" and "downcasting" and don't all have exactly the same meaning in mind when using those terms.
-Kevin P
04-03-2020 06:23 PM
Hey guys I've been fiddling with this a bit - created a bunch of classes. No real methods yet, wanted to focus on class relationships. BUT - sure seems like I went kinda crazy with the classes - this is like 3x more than I was thinking at first. Can someone help me with a sanity check? Did I in fact get carried away? Anduh - how come "Apply Icon to VIs" doesn't work? I have to go in and edit every child's icon - the demos I saw shows it happening automagically... Here's my classes in 2025 - thanks!
04-03-2020 07:53 PM
I'm no LVOOP expert, so don't take this as any kind of final word.
One key area of payoff is when you can take advantage of Dynamic Dispatch by having children implement specific behavior via override functions. So I'd encourage you to consider ways to design your hierarchy so that you *can* get this payoff.
For me at least, defining the needed *functions* is part of figuring out what the class hierarchy relationships should be. It's hard to say whether you've designed your hierarchy well or not until you also define what functions these classes have.
One brief specific comment. The very few functions you've defined *might* be a good candidate for a generic "Write Params" function. But to do so, you'd also need a more generic datatype for feeding in the variety of params needed by the different classes.
In the HAL I worked on, such things were always fed in as an XML-encoded string. This meant that the functions needed to parse through the XML to retrieve their actual typed parameters. (This HAL was part of a combined TestStand / LabVIEW implementation. If using LabVIEW alone, a Variant would be a more straightforward generic datatype to use for various classes "Params".)
-Kevin P
04-04-2020 08:18 AM
That makes sense Kevin. Interesting about using XML encoding, never heard of that. I guess it's 'self decoding', unlike, say, "Variant To Data.vi". Well, it is just plain ole LabVIEW, not Teststand. In the 'receivers' of the parameters, I would know the data type to extract them. Again, you've taught me something I had no idea of - thanks much!