To write a traversal algorithm of a set of data such that the traversal can be reused for many different operations.
Suppose I have an array of integers. I need a function that will calculate the sum of those integers (ignore, for the sake of argument, the fact that there’s a LV built-in function that does this). I drop a For Loop and iterate over every value, adding each element to a running total in an uninitialized shift register. The value in the shift register when the loop finishes is my sum.
Now suppose I want to find the product of those integers. I write the same For Loop and shift register, only instead of the Add primitive, I use Multiply. Everything about these two VIs is exactly the same except for the core action. How can I avoid duplicating so much code?
Dynamic dispatching does not immediately help in this case – I do not have any child types on any of the wires that I can dispatch on. I could make my traversal VI have a VI Reference input. Then, instead of using a primitive, I could use a Call By Reference node. The VI that I pass in would have either the Add or Multiply primitive.
This is helpful, but only works if my two VIs have exactly the same connector pane. What if I need other information, other parameters, to do the job in that Call By Reference node? What if there is more than one running total that I’m keeping track of? This pattern arises from the need to answer these questions.
Instead of taking in a VI Reference, the traverse VI takes in an object of class Action. This is a class that you define. Create one child class of Action for each specific action you want to do during the traversal. Then instead of a Call By Reference node, call the Do Action.vi method. This will dynamically dispatch to the correct implementation. The Action object can have all sorts of data inside it that can augment the operation at hand. You can implement new Action children without changing the original traversal framework.
The traversal VI can get very complicated, far beyond the simple For Loop over an array that I mention here. As the traversal walks over a data set, the Action object “visits” each piece of data and updates itself, which explains the name of this pattern. Your visitor can collect a summary of information about the pieces of data (such as the sum and product calculations), or it might search for a particular value, or it might even modify the data as it visits (divide each value in the array by 2). The traversal works just as well in all of these cases.
[Stephen Mercer] I am tired of writing LV2-style globals. These globals are great – very dataflow efficient, very easy to understand. But you have to duplicate the VI every time you want to support a different data type. I figured there had to be a better way. I’ve been thinking about this implementation for a while. It may not be optimal, but I think it is an excellent starting point. Imagine… the possibility of never writing another LV2-style global VI ever again, because you could just reuse one and give it the particular action that you want. A whole new flavor of über-geek nirvana!