LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Darren's Weekly Nugget 07/19/2010

Today's nugget has to do with the organization of data in a LabVIEW Class.  I have really only embraced LabVIEW Class programming within the past year, which probably makes me a late adopter compared to other LabVIEW architects.  But when I first started using classes, I took what I assume is a pretty standard approach to creating data member access VIs...every time I added a new data item to my private data control, I created read/write accessor VIs for that item.  One thing I noticed fairly quickly was that this really bloated the codebase of my LabVIEW Class-based apps.  It also became a maintenance headache when I needed to add/remove/modify items in my private data control, because I had to go add/remove/modify the data member access VIs as well.  So in my current LabVIEW Class-based project, I have taken a different approach:

 

19305i538094244C9E8DB2

 

In this example, my private data control now only contains a single element...and that is a typedef cluster (Harness Data.ctl in the screenshot above) that itself contains all the data items for my class.  With this approach, I now have a single read and a single write VI that gains me access to all the data in my class.  If I need to add/remove/modify items, I only do it in the typedef cluster, and the read/write VIs don't need to change.  The only disadvantage I've encountered to this approach is that each read/write in my code also requires an Unbundle By Name/Bundle By Name, respectively.  But I find this requirement to be much less of a burden than having to maintain a library of accessor VIs, especially since the adding/removing/renaming of VIs on disk is an extra headache when your project is in SCC, as mine always are.

 

I realize that this approach "publicizes" all the data in my class.  For my apps, whose interfaces have all been internal to this point, this is not a concern.  But I imagine for a LabVIEW Class-based app where there is a public interface, you would be going through extra work anyway to create public accessors for data, so as long as the Read/Write VIs that access the entire data cluster are private, it shouldn't be a concern.

 

One final note:  Since I am relatively new to LabVIEW Class development, I'm guessing there are theoretical reasons why this approach isn't the best.  But so far, I've found data member access to be a much easier endeavor with my current organization than with my previous.  So if you have any ideas about how my approach may break down in the future, speak up!

0 Kudos
Message 1 of 32
(7,855 Views)

Does this make searching for where a class data item gets accessed more tedious?  That is, with your previous method you could search on a discrete (cohesive) accessor VI.  Is there a suitable workaround for searching (e.g. during troubleshooting)?


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
0 Kudos
Message 2 of 32
(7,816 Views)

 


@LabBEAN wrote:

Does this make searching for where a class data item gets accessed more tedious?  That is, with your previous method you could search on a discrete (cohesive) accessor VI.  Is there a suitable workaround for searching (e.g. during troubleshooting)?


So far, I have found block diagram text searches for the data member name to be only slightly less easy than searching for instances of a single data member access VI.

 

0 Kudos
Message 3 of 32
(7,807 Views)

One slight catch that I can think of straight away with this method + source code control is this:

 

If you change the contents of your class's data cluster (ie add a new data member or something), every single VI that uses your Get/Set Everything VIs will end up getting recompiled etc whereas if you had separate data accessors, you would only have to re-save the VIs that actually changed.

 

This makes it much harder to track down the actual VIs that were changed as part of your "change".

 

It also makes it a whole lot easier to add bugs into your app - I'm sure I'm not the only one who has changed a type def cluster to later find at least one or two bundle/unbundle by name nodes got confused with the change.

 

Shaun

0 Kudos
Message 4 of 32
(7,784 Views)

If you add an element to your type-def then trying to read old versions of your class data from file will break.

 

I like the accessors since they let me selectively over-ride how where a value or stored and retrieved.

 

Example:

 

I need to be able to control the number of bits on a SPI bus. This is an option that my classes read from config file. When running, I need to enforce the proper number of bytes to carry those bits. My "Write NumBits" does the math and updates "NumBytes" within the accessor "Write NumBits".

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 5 of 32
(7,776 Views)

Ben, that example is one of my favorite features of proper data abstraction! 🙂

 

One thing though... I swear that I have saved classes to disk (using flatten to XML) and successfully re-read the data back into newer versions of the class with changed cluster type defs. In fact on of my templates for managing application preferences uses classes for this very reason (among others, obviously 😉 )

0 Kudos
Message 6 of 32
(7,762 Views)
One disadvantage could be performance. This approach will force a copy of your entire data cluster everytime. LabVIEW cannot currently discern the inplaceness of reading the cluster out of a subvi, modifying it and then writing it back into a subvi to store it back into the private class data. This same problem applies to individual element accessor VIs, but with a smaller performance impact.
Jarrod S.
National Instruments
Message 7 of 32
(7,687 Views)

I'm carefully watching this conversation because it addresses one of my primary hindrances for not choosing mainstream LVOOP in my development: the relatively low node-to-file ratio.

 

This results in high-overhead situations that hinder the development process: more files means more time to complete SCC operations, more time to complete FTP operations when deploying to a remote target (it's much faster to deploy ten 100kB files than one-hundred 10kB files), more window-acrobatics juggling with fewer nodes-per-window, and according to a project with a lot of classes just more time to do everything.

 

Darren's idea for mitigating this problem is ill-received (after 7 hours, his Nuggets usually have 10 Kudos - this one currently sits at 0). No one yet has said anything positive about increasing the node-to-VI ratio, which I find confusing... possibly the conversation should lead toward a new post on the Idea Exchange that attempts to reconcile both sides?

0 Kudos
Message 8 of 32
(7,674 Views)

Sounds like a job for scripting for me.....

 

I don't like the idea of accessing a cluster.  For me the data in and out of accessor VIs should be as "user-friendly" and fool-proof as possible.  One example is a set of LVOOP command parsers for instrument communication I have implemented.

 

If an instrument has a command of S012.4 made up of "S" for "Set", "01" for channel number and "2.4" for a voltage value then I don't want the user to have to enter the string "S012.4" directly because users are stupid and make lots of mistakes Smiley Wink  Instead I have the "S" as constant, have an enum for 01 to 04 (Because that's all my instrument supports) and a SGL with proper limits set for the final value.  Within my accessor VI I then convert to and fro between the aforementioned string and the allwoed values.  This way the user (programmer) is simply NOT ABLE to enter wrong values.

 

Of course I could do it like Darren says and simply have a cluster of "S", enum and SGL as a cluster but then I lose a decisive piece of my functionality.  My parent class contains a string as a data member and this class takes case or the messaging and instrument communication.  When accessing the data in my child class it is this string I am operating on, not a string in my child class.  My child classes are essentially command parsers.  I will still have to convert back and forth in order to have any benefit from this kind of inheritance in this situation.

 

This level of abstraction is extremely valuable for me and is a main reason why I like using LVOOP for implementing this kind of thing.

 

Shane.

0 Kudos
Message 9 of 32
(7,623 Views)

OK more thoughts on this topic.

I have run into the issue with having to remove accessors first before removing elements from the private data definition.

 

[Set blatent honesty mode]

 

But I only had to remove them becuase I screwed up and should not have had them to begin with! So I took those experiences as a learning opertunity and learned something from my mistake. What were the mistakes?

 

 1) I did not fully understand how to implement the right methods at the right level of the inheritance haierachy. Looking back at it, I was over-loading one of the levels and a result, was pinting myself into a corner.

 

2) I Cloned off the wrong level of the hierachy - Similar to above but I selected a prototype from which to create a new Class that had more than what I needed so I had to toss a lot of stuff.

 

So... For

 

#1 I learned to think more and try to keep my layers .... thin? For

 

#2 I either have to clean it up before introduction into SCC or if my Class hierachy is good, just crate a whole new class and implement over-rides for what is different.

 

Now back to the Accessors!

 

The Over-ride and inheritance power starts to kick-in when the class hierachy starts branching.

 

NOTE Still in honsety mode I got a preview of this when I was implementing a "Controls on the Fly" app in LVOOP. I modeled my classes similar to what NI did with controls and indicators. This was a good start for me since NI alredy provided a smaple outline. What I found was "The more classes I added to the hierachy, the less I had to code". I have deployed a few LVOOP apps since then and I strugled with getting good re-usable Classes... becuase I did not know what I was doing. Yes the apps worked fine, were easy to follow and modify but when I was done I did not find a lot of code that I could re-use Except... I found that the work I did with my Files to wrapp-up my TDMS functions let create a sibling class to handle the Config file stuff.

 

But now you may be asking "Why wrapp up NI functions?"

 

Taking to long to post, will contiue in next posting...

 

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 32
(7,579 Views)