LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Community Nugget 06/25/2007

Function Overloading in Producer-Consumer design
Part 1 of 3

First things first:
For this nugget, I'm going to assume people know what a Type Descriptor (TD) is.  If not, look here and here to find out more.

Type descriptor tool
Type descriptor info

We can access the TD from the "Flatten to string" function, right-clicking and choosing "Convert 7.X data" if using LV 8 or above.  TDs are internal descriptions of data being sent places within LabVIEW.  In essence, they are an inherent part of the data type.  We all know that if we connect a DBL to a SGL, we get Coercion.  This tells us that we have a data change going on.  If we connect two DBLs however, we don't see a coercion dot, which is of course expected. 


Does this mean that we have the exact same data type as before.  Not neccessarily.  If we look at the TD, it may be different. 

The clue is that the TD contains the NAME also, so the TD of two otherwise identical controls, but with different names have distinct TDs. 
So we can see that by accessing the TD of a control (or wire) we can differentiate not only based on data type, but also based on NAME.  This is important for later.



In Addition
I'm also going to assume you're familiar with producer-consumer designs.  If not, you can read about them here.


For a list of past nuggets, see here.
If you want to write a nugget yourself, see here.

Message Edited by shoneill on 06-25-2007 03:47 PM

Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
Message 1 of 51
(14,338 Views)
Function Overloading in Producer-Consumer Design
Part 2 of 3


In a producer-consumer design, each distinct command being passed between producer and consumer has a corresponding value on an enum (I prefer Enums over Strings).  Clustering this enum with a variant (Which can conatin any type of data) gives us a single universal messaging data structure of function name and variable data content.  By passing such a cluster with the correct enum and variant contents from the producer loop, we can call any of the implemented commands in the consumer loop.
Please ignore my spelling mistakes!

In this code example, we use some simple shape definitions to draw a picture.  We can choose between circle, square or triangle.  We can also set colour, rotation, X-Position, Y-Position and size.



PRODUCER

On to this example implementation: when looking at the producer loop, we see that basically one method is being called regardless as to which shape characteristic we're changing.  Depending on the change being made, the only difference in the message queued is the data type.

Sending a cluster:

Sending a DBL
Sending a U32

CONSUMER (Please reference the included LLB for these steps)



A:    Once the consumer loop receives the data in the queue, unbundling it gives us the function name and the variant data.

We're interested in the "Draw Shape" case.  We're actually handling lots of different distinct "function calls" within this single state.  We can pass the X-Position (DBL), Y-Position (DBL), rotation (DBL) and so on within the variant.  The job of this single state is to detect which case we're using and react accordingly.  This is kind of similar to having multiple API commands such as:

DrawShape(X-Position DBL);
DrawShape(Y-Position DBL);
DrawShape(Rotation DBL);
DrawShape(Color U32); and so on

B:    In order to first detect which datatype is being received, we need to read the TD of the data WITHIN the variant, not of the variant itself.  We then "clean" the TDs being used (See caveats below) and can then do a simple search for a "registered" data type.  The array input for the "Search 1D Array" is generated on the block diagram.  Consult the code for reference.

C:    If one is found, a subsequent case statement (Here depending on the index of the found TD) is responsible for incorporating this data into the correct cluster for our drawing routine.  At this stage, we have a routine which automatically receives a single command with different data and then incorporates this data into the proper place in a pre-defined cluster.

😧    The actual drawing routine always works with this same pre-defined cluster.

Run the VI to see how this works in practise.

The act of incorporating the data into a standard cluster COULD be automated for any given data types and the differences between the same function called with different parameters COULD be a lot more significant than I show here.  It depends on the application in question.  A universal "Include data" along these lines is feasible along and would probably be a nice exercise in getting to know LV data types.

I hope I have explained the principle behind my idea.  I hope some find it useful.  I know I do, regularly.

For a list of past nuggets, see here.
If you want to write a nugget yourself, see here.

Message Edited by shoneill on 06-25-2007 03:47 PM

Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
Message 2 of 51
(14,323 Views)
Function Overloading in Producer-Consumer Design
Part 3 of 3

I've been told that this method is more like "Virtual functions", and not "Function Overloading", one being checked by the compiler, the other at run-time.  Either way.....

Hint:
We are generating our "registered" TD array at run-time.  Any changes to the representation or name of any of the controls on the FP will change the outcome of our TD comparison.  This may break the code.

Since the name of the control is stored within the TD, a control with the same data type, but different name will NOT be found when comparing the TDs.  Please try out the "colour box" control on the FP.  Since the control we are comparing with is called "color box" (no "U"), the comparison will fail.  The message will be queued, but since the data type is unrecognized, the data is not used.

Caveats:
Type descriptors have reserved bits.  These need to be removed to enable comparisons.  This is done in the "TD Clean" VI.  This is a simple version of a "proper" version.

Type descriptors are not necessarily tied to a control.  They are inherent to data in LabVIEW.  This said, non-control TDs differ from those of Control TD in that the name of the control is missing from the non-control TD.  This means that we need to use a terminal within the event structure (which is good practice anyway) as the "newval" data has a different TD.....

Type descriptors contain the data type and control name(s) of any units within the control.  This is accessible from any wire originating from a control, even if it has been converted to variant.  To access the correct TD from a variant, we must use "Variant to flattened string".  This will return the TD of the data type WITHIN the variant, not of the variant itself.  This function has the unfortunate side-effect that it forces a buffer allocation.  For large data sets, this might be problematic.

Homework: Smiley Mad
Change the name of the "colour box" control on the front panel to "color box" (as in the cluster) and re-run.  The solitary colour box now works.

Change the data representation of any single control and see how this affects the functionality.

Attach the "newval" terminal to the "Queue element" instead of the control terminal (Producer loop).  See how the TD changes and the code breaks.

(for NI) Please give us the means to access the TD without creating a data copy.  And please don't get rid of the TDs completely!!!

(for NI) Even better would be native support for overloading such functions.  Or the ability to generate Polymorphic VIs where not only the data type is varied, but also the name (i.e. the FULL TD).....

For a list of past nuggets, see here.
If you want to write a nugget yourself, see here.

Message Edited by shoneill on 06-25-2007 03:48 PM

Message Edited by shoneill on 06-25-2007 03:48 PM

Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
Message 3 of 51
(14,322 Views)
Thanks for the nugget, it made me even more happier that I use OpenG tools on a regular base.
The tool 'Get DataName' digs the TD out and returns the name stored inside the TD!



Ton

Message Edited by TonP on 06-25-2007 05:31 PM

Free Code Capture Tool! Version 2.1.3 with comments, web-upload, back-save and snippets!
Nederlandse LabVIEW user groep www.lvug.nl
My LabVIEW Ideas

LabVIEW, programming like it should be!
Message 4 of 51
(14,251 Views)

Thanks for the Nugget Shoneill.  Very well explained. 

I do like the idea of a universal scheme to passing data to the consumer loop.  And variant seems to be the most versatile way of doing this.

For some reason, I remember during one of the NI-LV course that the instructor mentionned staying away from variants as a universal container for different data types.  I'm looking through my notes to find out why (hopefully I noted a reason) >> anyone from NI care to comment???

Don't get me wrong... I do like the approach. Personally, I think it's wonderful!!  🙂  It sure simplifies building a universal Event Structure / machine..  One that is very easy to add on more functionality.

Thanks for sharing!

RayR

Message 5 of 51
(14,232 Views)
I used to stay away from variant because they used to force data copies. I believe this has been improved (not sure).
 
What I am curious about is how well the change in the data type of the variants has survived the update to LV 8 and beyond.
 
Thanks Shane!
 
I will read more later.
 
Ben
Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 6 of 51
(14,226 Views)
Ben,

All code shown is in 8.2.1.  The TDs are there, you just have to look for them (right-click).

TonP,

I too use them, but I didn't want to make a Nugget dependent on external tools.....

JoeLV,

I believe the speed of working with Variants has been significantly speeded up in 8.2.

To all:  This is MY way of approaching this problem.  If anyone has variations or improvements, fire away.

Shane.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
Message 7 of 51
(14,210 Views)


@Ben wrote:
 
What I am curious about is how well the change in the data type of the variants has survived the update to LV 8 and beyond.
 
Ben


Thanks Ben!!

That triggered a memory cell..  Something to do with compatibility / support / future issue(s).

Message 8 of 51
(14,185 Views)
Nice nugget, although I'm also a bit afraid of something which already requires relying on old versions. I don't think the support would disappear anytime soon, but it wouldn't be developed either.

Another point - relying on undocumented features could give you some headaches later on. For example, in a recent thread there was someone complaining that the DB toolkit didn't work.
Why? Because when adding variants to the DB it relied on the internal structure to determine the size of the data. When that internal structure, the toolkit broke and NI didn't find it because they didn't test for that case.

JLV, one good reason for not using variants is that they are not strictly typed, so you can only catch errors at run-time. This is also something that speaks for them (for example, when you want to create this type of architecture), but there are other ways to do this as well.

@shoneill wrote:

I too use them, but I didn't want to make a Nugget dependent on external tools.....

It doesn't have to depend on them, but I see nothing wrong with taking some shortcuts. As a matter of fact,  having OpenG as the subject for a future nugget, just to raise awareness is on my list of potential nuggets.

___________________
Try to take over the world!
Message 9 of 51
(14,162 Views)

I'd love to see Nuggets based on OpenG VIs in the future.  It's freely available to everyone, so why not?

- Brad

0 Kudos
Message 10 of 51
(14,148 Views)