Friday, June 12, 2009

LabVIEW Scripting Tip #3: How to Handle References

Once you get past the really simple scripting apps, you'll quickly discover that your scripting VIs can become unwieldy at a moment's notice, and this is primarily due to how many VI Server references you have to deal with in a complex scripting app. Here now is a list of things to keep in mind when dealing with a plethora of scripting references all over your diagram.
  1. When to Close References - For every single VI Server reference type *except* VI and Application, it's fine to close the reference as soon as you're done with it. I've seen people write scripting VIs before where they thought they needed to keep each "parent" reference open as long as they were using a child reference. This is not the case. Check out this sample diagram, which is getting the first tunnel it finds on a Case Structure and determining if it is an output or an input tunnel:







    This code will work, but those wires don't need to span the entire diagram just to be closed later. You can imagine these wires could get very long as the complexity of your scripting code increases. Instead, take an approach like this:







    Here, we are closing the references as soon as we're done with them. The diagram looks cleaner, and we don't have to worry about passing really long wires around. Also, note the trick I'm doing with the array of Tunnel references. Often in VI Scripting, you'll have an array of references, but you're only interested in one of those references. In these cases, you can use the Delete From Array function to pull out the one you're interested in, and close all the rest.
  2. Comparing References - If you are trying to compare two references to see if they refer to the same object, you can simply use the Equal? function. Similarly, if you have an array of references, and you want to search that array to find the index of a particular reference, you can use the Search 1D Array function. Even though two references to the same object may have different flattened U32 refnum values (as can pretty easily be seen with the Type Cast function), using the comparison functions in LabVIEW will compare the actual objects those references refer to, and not the numeric refnum values, when performing the comparison.
  3. Checking Reference Type - Many times you'll have a reference to an object, and you'll want to figure out what type of object it is. You may be inclined to read the Class Name property of that object, but this approach can cause problems. For example, let's say you have a reference to a Node, and you want to see if it that Node is a member of the Structure class (Case Structure, While Loop, For Loop, etc.). So you read the Class Name property of the reference and see if it equals "Structure". Well, this approach will never work, because the Class Name property always returns the most specific class name of the object...so it would return CaseStructure, WhileLoop, ForLoop, etc. Instead of using the Class Name approach, you can use the To More Specific Class function and check the error output:






    In this case, as long as the Node is any type of Structure, the class conversion will succeed.
Does anybody have any additional tips for dealing with references when programming VI Scripting applications? Let's hear them!

7 comments:

  1. This is great to know, I've always kept my refs open until the last minute, closing them in reverse order. Life will be so much easier this way! I presume this works for ordinary (non-scripting) VIs too?

    ReplyDelete
  2. Yes, this works for all VI Server references *except* VI and Application. For those, you must keep them open until you are done. Also, this tip does not apply to other reference types...for example, with ActiveX, you must keep parent references open until you are done with their children.

    ReplyDelete
  3. There was a bug in LV 8.2 that required parent references to be kept open. This was true if the reference was to a control on a network machine and not the local machine. What a pain, it meant that you had to keep all those references around for a long time until you were done with the control reference.

    I am not sure if this was fixed in LV 8.5 or not. I didn't go back and remove all that code when I updated.

    ReplyDelete
  4. Interesting...I wasn't aware of any issues with the remote references case. I'll try to find some time soon to investigate in LabVIEW 8.6 to see if there is still a problem with closing parent object references over a remote VI Server connection.

    ReplyDelete
  5. Comment on point 1: I think as an alternative, we could just append all references to a 'garbage wire' (array of ref's), which is closed at the end. If we reverse it prior to closing, we even have the correct order.
    Comment on point 3: On the other hand, using the Class Name and wire it to a case structure (as shown by one of your nuggets in the NI forum) might be a better solution somtimes.

    Thanks for all the greate inspiration on that field. I hope we as user community soon come up with a set of tools.

    ReplyDelete
  6. WRT #3

    The one thing that I have found that you need to be very careful about when checking types is that if the 'to more specific' tosses an error, it also invalidates the reference. This matters if you use nested 'error case structures' to attempt multiple type checks (like you had a plot, but were trying to figure out what type)

    So in that case if you know that the 'to more specific' might toss an error then you must fork the reference if you want to use it after the failure to do another check.

    ReplyDelete
  7. On #1:
    I'm basically in the habbit of only explicitly closing references that I opened myself using one of the Open... primitives.
    I usually leave the closing of refs I obtain through methods or properties to LV. LV will close them as soon as the VI that contains those nodes is finished.

    I know it is not considered good programming practice (according to the LV help), but to me it just seems not naturally to close (destroy) a ref to an object I did not open (create). At ofcourse the second good reason is that my BD stays even more clean without all the Close primitives. :-)

    ReplyDelete