Sunday, February 8, 2009

Things That Have Bitten Me Lately, Part 1

Despite having been an active LabVIEW developer for the past ten years, sometimes I still fall prey to beginner's mistakes. Well, when I realize what the problem is, they feel like beginner's mistakes... sometimes, though, the root causes can be a little bit obscure. Today, we're going to discuss For Loops. More specifically, what can happen when a For Loop does not execute.

OK, so here's the scenario. I wrote a pretty simple subVI intended to write multiple key values to a config file. Nothing more than the Write Key.vi in a For Loop, fed by arrays of key names and values. Worked like a charm. Then I strung a bunch of these together, and noticed that some of my downstream groups of keys weren't being written. I stuck a bunch of probes along the chain of error clusters and noticed the ubiquitous -- and often confusing -- error 1 being produced. Then I similarly probed the file refnum along the chain, and lo and behold, one of the VIs was outputting an invalid refnum. Take a look at the diagram below and see if you can figure out the bug.
Here's what was going on: the offending VI was being fed a value array of length zero. Thanks to autoindexing, the For Loop wasn't executing. As a result, the input (valid) refnum wasn't being passed to the output. The rule of thumb with tunnels on For Loops is that, if they don't execute, the tunnel will take the default output value for the given datatype. With refnums, that means something invalid. Ooops.

The solution is really, really simple: replace the tunnel with a shift register. The shift register acts as a pointer to the input wire's value, so that even if the For Loop doesn't execute, the output wire will still point to the correct value. Problem solved. For the skeptical among you, try the code shown below.
We tend to think to use shift registers when we know that we will be changing a value of something from within a loop. In the case shown above, you'd naturally think, "well, the value of the refnum is static, so a tunnel in and out will be sufficient." It will be fine, as long as the loop runs at least once. So here's the new rule for For Loops: if there's a possibility that they won't execute, make sure that everything that needs to have a valid value gets passed through a shift register. Alternatively, you could just wire the refnum around the loop, but that ends up looking clumsy and ugly, and the style police will jump all over you.