Jan
07

Recursive Data Types in LabVIEW - making recursive data structures type safe

by Tomi Maila, Jan 7, 2008 at 4:15 pm
1 Star2 Stars3 Stars4 Stars5 Stars (4 votes, average: 5 out of 5)
Loading ... Loading ...

LabVIEW Object-Oriented Programming (LVOOP) was introduced in LabVIEW 8.20. LVOOP allows developers to build recursive tree-like data structures within LabVIEW dataflow model. Recursive data structures are enabled by allowing class private data members to be of ancestor class type. As ancestor class private data members can hold descendant class objects, recursive data structures are possible.

However LabVIEW doesn’t allow using recursive type structures where a type refers to itself. I present here that indeed building such types would be possible within the dataflow framework of LabVIEW. Such recursive types would allow building recursive data structures in more intuitive and type safe manner than what is possible with current LVOOP implementation.

Defining recursive types

Let’s assume that the private data of a class could have a data member of class itself. Let’s call the class A and the data member x which is now of type class A. The data member x has a default value, let’s call this default value x0. For the moment, let’s forget what the default value actually is, let’s just assume there is one.

LabVIEW stores objects (class instances) as references to a memory block. So what would happen if we drop a class constant with recursive data member on a block diagram. LabVIEW would need to create a constant memory block for the class constant object and pass a reference to this memory block on the wire originating from the class constant. Now the memory block allocation is a little problematic; we have a recursive type definition and if we would allocate memory in a conventional way, we would end up having an infinitely large memory block.

However, there is a workaround that would allow this kind of recursive type definitions without the infinite memory block problem. Let’s recall our data member x and its default value x0. Let’s assume that x’s default value x0 is something that is loaded into memory when the class is loaded into memory. Now when we drop a class constant on a block diagram, we would need to allocate a memory for an object. However we know that our object would be initialized to its default value. This means that also its data member x would be initialized to its default value x0. So instead of creating a recursive infinite memory allocation, we can set the object private data member to refer to the default value x0. We don’t have to allocate infinite memory block, we just need to say that the object private data member is of type class itself and its value is the default value x0. So the infinite memory allocation problem we had is now isolated into the default value x0.

So what would default value x0 be like then? We know that x0 is an object with a data member x and the value of x is x0. Now that x0 is a statically loaded object that doesn’t change during execution, we can set x0 to refer to itself cyclically. That is, x0 doesn’t need to allocate an infinite block of memory but instead simply refer to itself.

Accessing and modifying class private data

So far we have proven that a class constant can refer to itself recursively. What about other objects of a recursive class type? LabVIEW has four methods to access or modify the private data of an object namely unbundle and bundle nodes, always copy node and in-place element structure with unbundle and bundle terminals. We concentrate on the unbundle and bundle nodes as in-place element structure is only for performance optimization and always copy is trivial when not combined with unbundle node.

So what happens when we try to extract the value of x using an unbundle node from the default class constant object we have created by dropping the class constant on a block diagram? Now x refers to x0. We could simply return reference to x0 when x is accessed. However x0 is not a mutable object and if we would need to have a mutable object, or if we placed an always copy primitive after the unbundle node, we would need to return something else than simply a reference to x0. What we can return instead is a new object that refers to x0 in the same manner as our class constant object refers to the default value x0. The compiler optimization algorithm can then decide in which cases to return simply reference to x0 and when to return a new object that refers to x0. The unbundling of our non-recursive data members is trivial.

What about the bundle node then? Bundle node and in-place element structure bundle terminal are the only two primitives that directly modify private data of an object. To study this problem, let’s add a new data member to our example class A. Let this data member be called i and let it be of type int32 i.e. a 32-bit integer.

So in our example we can change the value of both the non-recursive private data member i and the recursive data member x. Changing the value of non-recursive data member i is trivial, it can be implemented exactly the same way as with conventional LabVIEW objects. What about recursive data member x then? Let’s assume we try to modify an object originating directly from a default value class constant. The before bundle node the object contains a private data members x and i. The value of x is a reference to x0. When the bundle node is executed, the value of x is simply changed to refer to the memory block that is wired into the element input x of the bundle node or its copy.

Linked List Example

As an example let’s study a class Linked List. The private data members of the class are a boolean has next and a Linked List next.

The default value of next is a static object next0 of type Linked List that refers to itself cyclically trough its private data member next. The default value of has next is in our example false.

Now when we drop a linked list on a block diagram, a default valued object is created i.e. an object with private data has next = false and next = next0.

Now creating a two-element linked list is possible simply by wiring one linked-list constant to the next element input terminal of bundle node of another linked list constant.

The data structure in memory after the above bundle operation is shown below.

Conclusions

I’ve shown that recursive data types do not contradict dataflow nature of LabVIEW and indeed recursive data types could be supported by LabVIEW. Any data structure that can be written with recursive data types as presented above can already be implemented with current versions of LabVIEW Object-Oriented Programming. However recursive data types add extra type safety to the data structures. In addition recursive types are more intuitive solution to many programming problems than using ancestor class object in class private data. For example the next element in a linked list is more naturally of type linked list itself rather than of type LabVIEW object as it would need to be in current versions of LabVIEW.

I didn’t go all the way proving with induction that all possible recursive type structures are actually dataflow safe. However I expect that the model presented here is extendable to type structures with indirect recursion and to classes with non-default value for private data members. Furthermore I expect the model to be extendable from classes to clusters if the cluster memory model is made more similar to memory model of objects.

Print This Post Print This Post

3 Comments

Make A Comment

Comments RSS Feed   TrackBack URL

Leave a comment