Today, we’re going to discuss how we want to extend the G language to model software capability. We’ll also dive into some deeper programming language and computer science concepts. If you use LabVIEW to program G, and classes seem like too much complexity for your application, then you don’t need to worry about this post. But if you love using classes in G, then read on!
What We Currently Have
Classes in LabVIEW allow G programmers to model the relationships between the objects that make up their test and measurement system. However, we have found that the notion of class inheritance alone is insufficient to represent the types of systems our customers build.
Programmers are interested in what the components of their systems can do, not just how they are related. Unfortunately, we don’t provide a clean abstraction to model the capabilities of a test system.
Why This Is Painful
Figure 1 shows two VIs that someone may write to measure voltage using a DAQ device and NI-DAQmx API in the first row and using a DMM and the NI-DMM API in the second row.
However, ideally, we want to write generic test steps, so that our test steps aren’t tied to specific individual devices. For example, we would write a test step that reads voltage, and in theory could take a device that implements a method named GetVoltage().
The third row in the figure shows such a setup. But where should the programmer define this GetVoltage() method? Both the DAQ device and the DMM can get voltage, but if she just defines this method at the leaf nodes she has duplicated code. The two methods, though they are named the same, have nothing to do with each other. If we define it in a common parent, let’s say an Instrument class, then all instruments must implement that method. Obviously, not all devices measure voltage (for example, signal generators). We then would lean on run-time error checking to make sure the right types get passed into the test step.
Furthermore, right now in the first two rows of the figure we see two completely different APIs. If we could write generic test steps that refer to an API based not on the device, but rather on the measurements we want to take, then the code becomes simpler. It’s useful to both abstract the hardware and the measurements, but the same mechanism does not work well for both, as we have discussed. Device characteristics and relationships fit well with class inheritance—using classes to write your hardware abstraction layer (HAL) is straight forward.
However, class inheritance doesn’t work that well for modeling the measurements you want to make because class inheritance doesn’t do a good job of modeling the capabilities of your test devices.
Figure 1. Without a HAL/MAL you must write different functions to read voltage. However, with a HAL/MAL and traits you could write one test step and pass in different devices.
Our Proposed Solution: Traits
Ideally, LabVIEW would have a way for you to define the required set of capabilities (that is, methods) that a class must have when we pass it into a VI. In the general programming language world, defining a set of these capabilities is called an Interface. But LabVIEW is special. G is a value-based language, which means that wires of a certain type always have default values. They aren’t referring to a value somewhere in memory; there is a value flowing along the wire. Furthermore, any VI is executable on its own. If we have a wire that represents the methods necessary, but doesn’t have an implementation because it’s just coming from a control on a top-level VI, what happens when we hit the run button on that VI? We would either throw a run-time error or invent some weird rules that would be hard to understand.
But what if we required the programmer to define default implementations of the methods on this interface? If you think about it, this requirement works naturally with how LabVIEW currently works. Imagine the class gtype editor, but without a data pane, just member VIs. The member VIs both define what methods are required, and the VIs themselves provide default implementations. In the general programming world, interfaces plus default implementations are referred to as Traits.
At the recent Certified LabVIEW Architect’s summit in Austin, we had some fantastic conversations about Traits and how they could fit into LabVIEW and G. We look forward to having more of these conversations with the community as we push these ideas toward production!