LabVIEW Development Best Practices Blog

Community Browser
cancel
Showing results for 
Search instead for 
Did you mean: 

When Should the 'To More Specific' or 'Preserve Tun-Time Class' Primitives be Used with OOP in LabVIEW?

Active Participant

Today's entry was inspired by a question I recently received from someone while presenting at Developer Days in Salt Lake City - I was asked, "when and why should I use the 'preserve run-time class' node, and what's the difference between it and the 'to more specific' primitive?" It was a good question, and something that I didn't fully understand myself until I spent some serious time doing object-oriented programming. What follows is my attempt to explain this for anyone else who might have ever wondered the same thing.

The 'to more specific' node is a mechanism to tell the LabVIEW compiler that an object is guaranteed to belong to a certain class of objects.  Without this assurance, the compiler has no way of knowing what the object belongs to or is capable of at compile time, and would therefore show a broken wire if you attempted to pass the object wire into a function that can only act upon a certain class of objects.

Perhaps the most common illustration of this is a plug-in framework using classes (also known as a factory pattern).  A factory pattern enables you to add or change functionality simply by loading a new child class at run-time.  It is required that the calling application already have in memory a common parent, but the newly loaded child class can then override or extend the behavior of dynamically dispatched methods.  As an example, a framework may already be written to act upon a generic measurement, which has methods to initialize, acquire and analyze a signal.  A specific measurement, such as a frequency sweep, could redefine the implementation of these methods.

Shown below is the code required to load a specific measurement at run-time.  The 'Get LV Class Default Value.vi' brings a class into memory from a location on disk, but the compiler has no way of knowing the type of object prior to this operation.  This is why we use the 'to more specific class' node, which then allows us to treat the object as belonging to a specific hierarchy - in this case, we treat it as a measurement.  Note that the error handling is designed such that we only add the loaded class to the array if it is a valid member of that class hierarchy.  If we had not handled this correctly, and we attempted to load an invalid class, this node would return the parent 'Measurement.lvclass' object.

A.png

The 'preserve run-time class' node is also a way to give the LabVIEW compiler a guarantee that it would not otherwise have at compile-time - in this case, we are telling the compiler exactly what class of object will be passed out.  The primary use-case for this node is within a VI that has a dynamic input terminal and a dynamic output terminal for the same class, but there is not a guarantee that the object's class will be preserved between them.  If, for example, we are dynamically loading an object that will replace the object that was passed into the VI, the compiler has no way to know what class the object will be, and will therefore have a broken arrow.  'To more specific' cannot be used in this case, as we need to guarantee the exact class of the object.

In the example below, the other case of the case structure is set to 'Use Default' for the class wire, which means that LabVIEW does not know at compile-time what the class of object is that it will receive. The first diagram of 'common.vi' attempts to use 'to more specific' to indicate that the object will be a child of 'Hardware.lvclass,' but it still does not guarantee that it will be 'SCOPE.lvclass.'  As a result, the calling VI, initialize.vi, which has dynamic input and output terminals, is broken, as it needs to know that the exact same class of object will be passed between.

B.png

The diagram below shows how we use 'preserve run-time class' to guarantee that the class of the object will be the same as it receives.  As a result, initialize.vi can compile and we no longer see a broken run arrow.

C.png

This illustrates the most common and important use case for 'preserve run-time class.'

As always, you can find more information on these in the LabVIEW help, but free to post questions and comments!

Eli

Elijah Kerry
Chief Product Manager, Software Platform
_______________________________________________
Follow my Software Engineering for LabVIEW Blog
Comments
Active Participant D60
Active Participant

Dear ElijakH,

Thanks for your blogpost. To tell the through I have never used the preserve run-time class before. I saw many implementation where the preserve run-time class is used as "instance of" but this test can be achieved by using to more specific class also.

I hope there will be some posts where the power of preserve run-time class mentod will be demonstrated becase the Labview help shares little info about it.

---
+++ In God we believe, in Trance we Trust +++
[Hungary]
Proven Zealot

> but this test can be achieved by using to more specific class also.

No, it cannot. Those two primitives do two different tests. The "To More Specific" tests the incoming object vs the type of the wire at the middle terminal. The "Preserve Run-Time Class" tests the incoming object vs. the type of the object on the wire at the middle terminal.

Member D*
Member

Perfect explanation.  You should add this as an example to the help file for this function.  Also, while the title of this post alludes to the Tun of Fun that OOP is, you probably should adjust the title of this post so that other that are searching can find it.

Member

One thing I want to add to this to help if there is any last confusion:  If you use the To More Specific node and pass an object into it, it will error out only if the Reference Object is not the same OR a child of the Target Object.  If you use the Preserve Run-Time Class, it will error out if the Reference Object is not the exact Target Object. 

In other words, "To More Specific" accepts the Target Class or any child classes of the Target Class at Run-Time, hence why it works for a plug-in framework where you specify a parent Target Class and then load in a bunch of children of that Target Class.  It only errors out if it attempts to load a class that is not a child of the Target Class.

"Preserve Run-Time Class" only accepts the exact Target Class and does NOT accept any child classes of the Target Class, hence why it would not work for a plug-in framework.  The use case provided above is a targeted reason for its use.  Another use case would be if you were sending objects across a network and needed to guarantee that the object at the other end is an exact class and NOT any of the children classes.

--

Chris Fronda

Founder | Certified LabVIEW Architect

VI Design Group, Inc.

NI Certified Alliance Partner

www.VIDesignGroup.com

Chris Fronda

Principal Engineer | Certified LabVIEW Architect
VI Design Group, Inc.
NI Certified Alliance Partner
www.VIDesignGroup.com
Mobile # (469) 767-6335
Proven Zealot

Chris is generally right, but his imprecise phrasing is the kind of phrasing that has mislead people before. I know he has the right idea, but I want to make sure others get this right.

I struck out a small amount and added the text in boldface.

> One thing I want to add to this to help if there is any last confusion:  If you use the To More Specific node and pass an

> object into it, it will error out only if the By-Value or By-Reference Object is not the same OR a child of the

> Target Object wire type of the Target Object input; the runtime object is ignored entirely.  If you use the

> Preserve Run-Time Class, it will error out if the By-Value Object is not the exact same

> type as the runtime object passed into Target Object.

Preserve Run-Time Class does not work for reference types.

Member

Thanks for specifying

Chris Fronda

Principal Engineer | Certified LabVIEW Architect
VI Design Group, Inc.
NI Certified Alliance Partner
www.VIDesignGroup.com
Mobile # (469) 767-6335
Member

Also...to follow-up on what 'AristosQueue' stated in case there is any confusion:

Control refnums and .NET refnums and DVRs of classes are by-reference objects

LabVIEW classes are by-value objects

My statement above was specific to LabVIEW Classes (by-value objects).  AristosQueue expanded the statement to all LabVIEW Objects (by-ref and by-value) and their respective behavior.

--

Chris Fronda

Founder | Certified LabVIEW Architect

VI Design Group, Inc.

NI Certified Alliance Partner

www.VIDesignGroup.com

Chris Fronda

Principal Engineer | Certified LabVIEW Architect
VI Design Group, Inc.
NI Certified Alliance Partner
www.VIDesignGroup.com
Mobile # (469) 767-6335
Member

Hi Chris,

You mentioned:

Chris Fronda wrote:

"Preserve Run-Time Class" only accepts the exact Target Class and does NOT accept any child classes of the Target Class, hence why it would not work for a plug-in framework.

However, I'm seeing something different, in LV 2014 at least. When I wire an object to the target of the Preserve Run-Time Class primitive that is a parent of the object wired to the object in terminal, I see no error and all class data is intact.

What am I not understanding?

Thanks.

Member

Here's a code example to better explain my last post. I have a class hierarchy where Animal is the common ancestor to the child classes. Here's the hierarchy:

lv class hierarchy.PNG

Here's the test VI I'm using to help me understand the differences between "To More Specific" and "Preserve Run-time Class":

class test vi.PNG

So what I'm doing is creating an array of all of the objects in the hierarchy, including the generic LV object so that the wire/compile type of the array and of each object in the For Loop is of LV Object. I'm iterating through each object in the array and performing both a "To More Specific" and "Preserve Run-Time Class" operations on them.

I've also taken the Felidae object outside the For Loop and wired it to the "To More Generic" primitive with the parent class of Animal as the target. The output of the "To More Generic" primitive is of Felidae run-time/object type, but of Animal compile/wire type. This is wired to the Target terminals of both "To More Specific" and "Preserve Run-Time Class" primitives. So "To More Specific" should be testing objects coming in against Animal and it's hierarchy and "Preserve Run-Time Class" should be testing objects coming in against only the Felidae class (and not its children [Lynx, Cat, and Tiger]).

I'm also logging errors thrown by each primitive at each iteration. Based on what I've read, I should expect errors thrown by the "To More Specific" primitive only during the first iteration since the LV Object is the only object in the array not equal to the wire/compile type of the target object nor is the LV Object part of the target's hierarchy. The target's class in this case being Animal.

I would also expect that errors to be thrown by the "Preserve Run-Time Class" primitive in every iteration except for iteration number 3 where the run-time types of both the target and "object in" match. The target is always Felidae for this primitive and the object at index 2 of this array is a Felidae object.

My expectations are correct for the "To More Specific" primitive but not for the "Preserve Run-Time Class" primitive. Errors are not thrown for the children of Felidae (Lynx, Cat and Tiger).

class test FP.PNG

Can someone explain this behavior? What am I missing?

Thanks!

Active Participant

To More Specific and Preserve Runtime Class don't actually change the object on the wire at runtime - this never changes. They simply help you treat the object as the type at compile time "Hey compiler, I know what I'm doing. You can make this assumption for now". This way you can write code that should work at runtime but the compiler can't guarantee at compile time.

The Preserve input is still (on the wire at runtime) type Felidae, although at compile time you are treating it as something else. The Preserve thus doesn't generate an error for this type (and it's descendents) since they can all be preserved as that class.

Active Participant

amandion wrote:


                       

Hi Chris,

You mentioned:

Chris Fronda wrote:

"Preserve Run-Time Class" only accepts the exact Target Class and does NOT accept any child classes of the Target Class, hence why it would not work for a plug-in framework.

However, I'm seeing something different, in LV 2014 at least. When I wire an object to the target of the Preserve Run-Time Class primitive that is a parent of the object wired to the object in terminal, I see no error and all class data is intact.

What am I not understanding?


                   

Chris is mistaken (or wording things unclearly); the difference between "To More Specific Class" and "Preserve Run-Time Class" is that the former compares the input object class to the class of the wire type input up top, while the latter compares it to the class of the actual object input up top (known only at run-time, hence the name).  Otherwise they are the same, and both will accept objects of child classes of the comparison object. 

Member

OK, I get it now. Thanks everybody!!