LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Can child accessors return different data types from parents?

Basically I want to be able to do the following, but with my own classes:

 

Variant vs concrete.png

 

I can call the property node "Value" on a Numeric control, a String control, or a generic Control, and I get different data types depending on which specific reference I call. Can I get this behavior with LVOOP classes, where I could return child-specific values when wiring with a child wire, but a variant (or other) when wired with a parent wire?

 

I don't believe these control properties are implemented as standard LVOOP classes (hence the awesome QControls). I'd like to be able to define some sort of hierarchy where a parent class returns a variant, but child classes can return their own specific datatype similar to the way "Numeric" controls are handled versus a generic "Control".

 

I can't have a parent class called "GetValue" with Variant as an output, as my Child classes would have to have their overrides return a variant as well. I could have a parent GetValue that calls private "GetChildValue" methods that children must override with their implementation of "Convert to Variant", but then I'm not allowed to have a child GetValue that returns the specific child data type, as I'd have already used that name in the child class.

 

I wonder if this is possible using malleable VI's (which I haven't used yet but look promising. I also wonder if I'm overthinking things, and there's a really simple way to do this, or if I'm trying to pick at an anti-pattern. Since LV does it internally it seems like it's a good way to go if I could figure it out 🙂

 

(To answer "What are you really trying to do here?", I'd like to implement something very similar to the above but that returns an array of U8's that represent each subtype as a flattened byte array. Each of my subtypes have an element that's a certain value type, but has more information than JUST an I32 or String or whatever.)

0 Kudos
Message 1 of 19
(3,146 Views)

I do not LVOOP that often so...

 

Composition pattern?

 

How about having the Parent return a "data" class that is the ancestor of the children of "Data" classes that are returned for each of the children. I think that is what the "friends" setting is intended to be used for in the Class settings.

 

Saying it another way...

 

For Each class you have, included another Class type in the private data. When each of your classes initialize they insert THEIR data class in their private data. 

 

All operations done on the returned data will have to be handled by methods in each Data child class.

 

Just throwing out ideas,

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 2 of 19
(3,138 Views)

The big problem with doing this in an inheritance type structure is that there is a requirement that dynamic dispatch classes have identical front panel connections (presumably to prevent issues with trying to grab class data that doesnt exist), so if you want to do proper dynamic dispatching of the classes you are limited to having the output be a high level data-type (string/variant).

 

If you are happy working with a static dispatch structure you can use something similar to the structure I have used as shown in the images where the children access the parent data and convert it to their appropriate types.

 

Child method, reading parent data spaceChild method, reading parent data spaceParent method, accessing generic data-spaceParent method, accessing generic data-space

 

 

 

High-level operationHigh-level operation

 

 

Message 3 of 19
(3,097 Views)

Why not just use a Malleable "vim"?

 

They are fairly easy to use and if you search the example finder....Oh, hey! That's a great idea Jeff!

 

You'll run into a nice project that has a lot of great advice in its documentation.


"Should be" isn't "Is" -Jay
Message 4 of 19
(3,089 Views)

To expand on Jeff's point, since 2017 SP1, and expanded in 2018, LabVIEW's VIMs can be used to take different (not related) classes that have the same named member VIs and suitably related connector panes (including a class input, which does not need to be but can be dynamic dispatch) to implement this kind of functionality.

 

Attached is a simple and totally non-interesting example showing two data types. Note that you can't form an array of these in a useful way (they would form an array of LabVIEW objects, which don't implement the "Read Value.vi" necessary for "Read Value VIM.vim". The example is saved in 2017 (SP1, not that it's important for opening, but it is necessary iirc).

 

example.png

broken.png


GCentral
0 Kudos
Message 5 of 19
(3,083 Views)

Just because I wanted to try this out I've gone through and made up this class so that it can be used as a base.

 

Due to class requirements, the accessor can't be a VIM so you need a wrapper but if you make that dynamic it can be called from any children class.

 

All in all actually a pretty tidy little layout...

 

 

VIM.PNG

 

Message 6 of 19
(3,065 Views)

Just as a note:

Your accessors are NOT returning different datatypes as was originally requested in the first post.  Instead, you have defined a new datatype which acts as a container for whatever you require.

 

This is a distinction. The fact that children cannot return a different datatype to their parent for overriding an accessor remains. The only option left is to choose a datatype which can handle this (Variant, String, Object).

 

It's a minor point (after all, you probably just want working code) but it's worth mentioning that the semantics are different.

0 Kudos
Message 7 of 19
(3,035 Views)

@Intaris wrote:

Just as a note:

Your accessors are NOT returning different datatypes as was originally requested in the first post.  Instead, you have defined a new datatype which acts as a container for whatever you require.

 

This is a distinction. The fact that children cannot return a different datatype to their parent for overriding an accessor remains. The only option left is to choose a datatype which can handle this (Variant, String, Object).

 

It's a minor point (after all, you probably just want working code) but it's worth mentioning that the semantics are different.


Yes.

 I think the fancy term is "LV has strictly typed data" which is what the wires are all about.

 

But we can turn the question inside out and skip getting the data OUT and letting the data do its own thing.

 

The examples above are trying to create an array and the best we can do is the variants string or objects as Shane pointed out. But instead getting it "out" use that data that is IN the data objects.

 

Say we want to generate a report that includes the data from different various children. If we create a method in the parent class that is called "Add data to report" then each of the children can add their data to the report since they know what their data is like. That way the data never is "returned" but rather used inside the child override methods.

 

Just my 2 cents,

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 8 of 19
(3,016 Views)

@BertMcMahan wrote:

(To answer "What are you really trying to do here?", I'd like to implement something very similar to the above but that returns an array of U8's that represent each subtype as a flattened byte array. Each of my subtypes have an element that's a certain value type, but has more information than JUST an I32 or String or whatever.)


Although I think possibly some of the solutions so far have shown ways to get type-specific accessors with VIMs (including the possibility of Variants for the parent type if you group your classes with an inheritance heirarchy, which may or may not be something you want to do), as Ben just pointed out, it might not be the case that the solutions so far are the simplest/best way to accomplish the stated goal.

 

Using a single malleable VI and the Type-Specialization Structure might be a much simpler and easier to implement version of what you're looking for. By using the 2018 type-assertion nodes and providing a case at the end which correctly handles any type (i.e. a default case) you could provide type-specific handling for various datatypes, whilst falling back on something like the Flatten to String and String to Byte Array nodes if you don't have a specific way to handle your type.

 

Would that work out better for you?


GCentral
Message 9 of 19
(3,010 Views)

Still thinking out loud...

 

When I have a bunch of plug-ins that needed to be configured with the config info that applies to them, I avoid making the code that invokes the plug-ins to have to have the knowledge of what each plug-in needs to know ( I think it the Expert Pattern that says something like assign responsibility to whatever knows about the work) I pass a ref to the config file to each of the children and invoke a method like "Go Init Yourself".

 

So again, let the class do what needs to be done instead of tangling up the caller in the details.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 10 of 19
(3,004 Views)