Wednesday, March 25, 2009

There Are No Strict Type Definition Constants

Type definitions (aka typedefs) are very useful. However, they also have some unexpected behaviors that can cause you a lot of trouble.

As a usability advocate, it pains me every time I have to explain this one, but here it is: There are no strict typedef constants in LabVIEW.

I am not going to try to defend this as "good" behavior. But it's not a bug when constants linked to strict typedef files only update on type changes.

Basics of Custom Controls


LabVIEW has three kinds of custom controls (.ctl files).
  1. Unlinked custom control. A "regular" custom control uses a definition (.ctl) file but the instances are not linked to the definition file. Thus, when you edit the .ctl file, instances that were created from it in the past do not update.
  2. Linked by type (aka typedef or type definition). Whenever the definition (.ctl file) changes type, all instances need to update. If the instance is set to auto-updating, it will update itself on load. [Note, however, that it will not auto-update while the definition file is open in the control editor.] If not set to auto-updating, you must right click on each instance to update it.
  3. Linked by all attributes (aka strict typedef). Similar to a typedef, except that any time the definition changes, all instances must update. This is achieved by time stamp comparison between the definition and instances. The intent is to have all instances cosmetically identical to the definition. Since most cosmetic attributes are invalid on the block diagram, there is no such thing as a strict typedef constant. Constants linked to strict typedef definitions act like typedef constants.


Confusion Over When Typedefs Update

If you have a ring, its type is its numeric representation, e.g. unsigned word.

If you have an enum (which can look identical on the front panel), its type contains its item names.

Thus, when you add items to a typedef ring definition file, the instances don't update (because the type didn't change). When you add items to a typedef enum definition file, the instances do update. However, if you make a strict typedef ring, then control instances will update when you add items. But since there's no strict typedefs on the diagram, constants that are linked to a strict typedef ring will not update when you add items. This behavior is confusing, but it is working as designed.

Forcing Updates


Even though typedefs only update when types change, instances get cosmetic changes from the definition whenever they update. So one trick to "push" changes to typedef instances is to change the data type, apply changes, and then change the data type back. [edit, March 26 - Note that the typedef instances need to be in memory when you use this trick].

Unreliability of Data


Another potential problem with typedefs is that you shouldn't rely on them keeping their data values when they update. LabVIEW will attempt to preserve data. For example, if you have a typedef numeric constant and change its representation, LabVIEW will convert the value. However, there are many cases where LabVIEW will not preserve the values correctly, especially with clusters, so it's a good policy not to rely on the values being preserved. (Or to visit all the typedef instances when you make changes, in order to verify their values).

Why Use Typedefs?


I would be remiss if I didn't make a case for using typedefs despite the potential problems that I've covered here. Typedefs let you change the type of all the instances with a single edit. This is very useful, for example, when you have a set of VIs operating on a cluster and you later realize you need to add or remove items to it. Without using a typedef, you have a lot of broken wires until you visit every VI that passes the cluster in or out of its connector pane. And strict typedefs are extremely valuable for maintaining consistent user interfaces - you can make controls on any number of VIs have the same appearance.

One final note - if you're using LabVIEW 8.2 or later, and you want to use a typedef so that you can encapsulate data for passing between VIs, then you should consider using a LVClass instead. You may still choose to use a typedef, but it's good to evaluate, because LVClasses serve the role well and give you a lot of other benefits as well.

[Please ignore this edit. I'm trying to see if updating an older post makes it show up on my blog mirror on NI Communities, without causing ill effects.]

6 Comments:

Blogger Darren Nattinger said...

Regarding the "Unreliability of Data" section, there is a VI Analyzer Toolkit test called "Typedef Cluster Constants" that will detect any cluster constant on the diagram that contains non-default values. The purpose of this test is to detect the very situation you're describing here.

11:23 AM, March 26, 2009  
Blogger Christina said...

Thanks for the additional info, Darren! The VI Analyzer is a great tool. You should talk about it more on the LabVIEW Artisan blog!

11:35 AM, March 26, 2009  
Blogger jeffrey said...

Thanks for this clarifying post Cristina.. I actually had this one on my todo list for submitting a bug-report.
I don't use rings often, but in this particular case they seemed to be the best alternative due to the lack of sparse enums.

What I now do to also update the constants on the (many) BD's that use the strict typedef, is a search and replace on all VIs in my project and then do a save all.

5:02 PM, March 26, 2009  
Blogger Christina said...

Jeffrey,

You are correct, the lack of a sparse enum means you have to use rings for those use cases. The search and replace certainly works - sorry that you have to do something so tedious! This also reminded me to add to the main post that the "toggle the data type" trick only works on typedef instances that are in memory.

Thanks for the comment!

5:33 PM, March 26, 2009  
Anonymous Carolyn said...

I find Type defs Extremely useful. For a long time, I avoided them, because I didn't really understand what they would do for me. On a large project, I dove into them and now I don't see how to get by without them. There's an article on this in Tips And Tricks.

2:46 PM, June 22, 2009  
Blogger Doug said...

I ran into the ring strict typedef not updating issue the other day (and Google brought me to this post). Thanks for the explanation.

In my case I wanted to use the ring to index an array. I really wanted to keep the automatic updating that comes with adding a string to an enum strict typedef, so I changed the ring typedef to an enum, thinking I would then cast the enum output to an I32. To my surprise, the cast was not necessary. It appears that Index Array grabs the value from the enum typedef, in contrast to how the Case Structure grabs the list of strings. Problem solved for me.

11:13 AM, July 23, 2009  

Post a Comment

<< Home