Sunday, August 27, 2006

Code Reuse through Classes

Before LabVIEW 8.20, code reuse primarily meant writing good subVIs. With LabVIEW 8.20, you can also reuse code with well-designed classes.

Let's look at the OO GSW example from my previous post. There are two kinds of code reuse demonstrated here: inheritance and delegation.

If you look at the LabVIEW Class Hierarchy window (found in the View menu), you can see that all the different link handlers inherit from a Link class. Making a common ancestor class allows us to do several things: put common data fields in the Link class private data; share common functionality in methods on the Link class; and define interfaces for dynamically dispatching on this hierarchy of objects (more on this last point in a future post).

Having a common ancestor class also allows us to create arrays where each element is a different class. That's right, that means having an array where each element is a different type! And because of dynamic dispatching, you can iterate through an array, call a particular method on each element, and dynamically call an appropriate VI to do that operation on that type of object.

Of course, you may notice that you actually get the ability to create arrays of different classes automatically. In the LabVIEW Class Hierarchy window, you can see that all classes in LabVIEW inherit from a common ancestor class. We call this class LabVIEW Object. It has no private data or methods, and you cannot edit it.

You may also notice, in the LabVIEW Class Hierarchy window, a second class that inherits from LabVIEW Object called ProjectWizard.

When you have certain modules (like Real-Time) installed, the Getting Started window changes. One of the links in the New section becomes a link to a module's New Project Wizard. Also, a Targets ring becomes visible in the lower left, which shows all the module project wizards available. Clicking on the new project link in the New section or selecting the corresponding item in the ring and clicking Go both do the same thing.

I designed my class hierarchy with two kinds of links: clickable text and ring items. In the module New Project Wizard case, there are links of each type that need to share functionality. Should I put the common data and methods in the ancestor class, Link? No, because then all the kinds of links that don't open project wizards would needlessly share them.

Instead, I create a helper class that launches project wizards, and I put an object of that class in the private data of both ProjectWizardClickableText and RingItemProjectWizard. This is called delegation.

As I've said before, there's lots more to talk about on this example, but I want to keep each post short, so that's all for today. Thanks for reading!

Labels:

Tuesday, August 22, 2006

An Object-Oriented Getting Started Window

Today, I'm going to share with you a feature that's currently in development for a future version of LabVIEW. It's a new version of the Getting Started Window (GSW).

My goal for this project is to change the content definition of the GSW to a user-configurable XML file. (This means you will be able to change the items on the right to the functionality of your choice).

My approach used LabVIEW Object-Oriented Programming. I'm sharing this with you because I think it is a good example of several LabVOOP principles.

Disclaimer: I am providing these VIs only as an example. Although they are a functional replacement for the Getting Started Window that shipped with LabVIEW 8.20, they have not undergone the verification and validation of a released product.

(edited January 22, 2007) The VIs are no longer available on NI's FTP site. If you e-mail me at my gmail account, I can send them to you.

(edited August 21, 2007) There is a shipping example in LabVIEW 8.5 (Navigation dialog) that is a simplified version of these VIs. You can download the same files in LabVIEW 8.2.1 format here).

I highly recommend that you explore the VIs using the project file, which organizes them into a hierarchy. A few of the subVIs are password-protected, but I don't think they interfere with seeing LabVOOP in action. You can run the top-level VI (GSW_Main.vi) and stop it by clicking the close box on the window.

The general idea of the design is that the panel contains buttons for the links, and I associate each button with a handler object that defines the button's displayed text and the functionality when the user clicks it.

There's too much to discuss in a single post, so I'm going to be talking about this example for awhile.

Labels:

Thursday, August 17, 2006

Dynamic Dispatching

Encapsulation and inheritance are good features, but the part of LabVOOP that I believe really takes the cake is dynamic dispatching.

Dynamic dispatching is, however, a little difficult to explain. Here goes...


Consider this diagram snippet. We have a wire of a certain datatype, carrying data of a certain datatype, passing that data into a subVI.

Before LabVIEW 8.2, you knew for certain that the data on the wire was the same type as the wire, and that the VI that opened when you double-clicked on the subVI was the one that would execute at run-time.

Both of these are no longer true.

A wire of a class datatype can carry data of that class or any class that inherits from it. So, using our previous example, a Link wire can carry a Link object, a Web link object, or a VI link object.

Dynamic dispatching gives you the ability to call a different subVI, depending on the datatype of the input data. It is run-time polymorphism.

I think this is easier to show with an example, so I'm going to provide one with my next post. Time to get those copies of LabVIEW 8.20 installed! :-)

Labels:

Tuesday, August 15, 2006

The Class: a Cluster of Clusters

Imagine you have some buttons that open web pages when you click on them. You have, for each button, a cluster of the display name and the URL to open when the button is clicked. Now you want to have some buttons run VIs when the user clicks on them, so you make another cluster with the display name and the path of the VI to run.

Well, this isn't really satisfactory, is it? Display name is duplicated in both clusters. And you can't make an array that includes both kinds of links.


Another approach might be to make a unified cluster, with the display name, URL and path. But now you need a way to know whether the URL or the path is valid in a given cluster, so you'd have to add some kind of selector. And, as you add new kinds of links, this cluster is going to grow and grow.


What you really want is to put the common fields in one cluster, and the fields for each specific kind of link in other clusters. This is where classes can help.

So... when I said you can think of a class as a cluster, I kind of lied. Really, you can think of it as a cluster of clusters. If Link is the parent class, and Web link is its child class, then the data for a Web link object includes both the Link private data cluster and the Web link private data cluster.

This is called inheritance. It lets you break out the data and behavior into a logical hierarchy. There's lots more to say about this, but I'll leave that for future posts.

Labels:

Sunday, August 13, 2006

The Class: the Black-Box Cluster Typedef



Classes are fundamental components of object-oriented programming.

In LabVIEW 8.2, you can think of a LabVIEW class (in an extremely simplified view) as a cluster and the VIs that operate on it.

To VIs outside of the class, an object (an instance of a class) is a black box... or, more accurately, a blue cube. They cannot directly access an object's private data (the elements of the cluster).

VIs that are members of the class can bundle and unbundle the class data as if it were an ordinary cluster.

This is called encapsulation.

So, what is this good for? Lots of things, but I'll only list two here:

  • Data modification choke points. If you want to set some probes to find out where a private data element is changing, you know you only have to set them in VIs in the class.

  • Interface stability. If you decide to change your private data (e.g. adding a new element), none of the VIs that use your class have to change, unless they want to use the new element.


You might argue that you could achieve both of these benefits by using a cluster typedef and a set of VIs that read/write the values of each element. And I would agree. But without using classes, there would be nothing to prevent someone from writing a VI that circumvents your plan and accesses the cluster directly.

And, of course, there's much more to object-oriented programming in LabVIEW, as we'll see in future posts...

Labels:

Object-Oriented LabVIEW

Back in 1998, when I was on the road presenting the new features of LabVIEW 5.0 to customers, a gentleman asked me if there were any plans to make LabVIEW object-oriented. I asked him what aspects of OO he was looking for, and he smiled and admitted he didn't know. But it was something that other programming languages had.

Now it's 2006, and with the release of LabVIEW 8.2, we have object-oriented programming in LabVIEW. But from my conversations at NIWeek, it seems to me that many people don't really know what that means, or how they can benefit from it.

So I'd like to take a little time to discuss LabVIEW Object-Oriented Programming (LabVOOP) from my perspective: the point of view of someone who has spent years using LabVIEW and is familiar with object-oriented concepts, but had not tried to use the third-party OO tools that were available in the past.

Over the next few weeks, I'll explain various aspects of the OO features of LabVIEW 8.2. I'll try to post in "bite-size" chunks so you can all journey along with me from the ground floor up.

I'll warn you at the start that OO is not some kind of magic cure that will fix all your problems. I view it as another tool in your VI development toolbox. But I eagerly anticipate seeing what people will build with it.