The seeds of object-oriented programming might be traced back to the concept of the API (application programming interface). An API is basically a piece of paper that defines a set of subroutines and the behavior an application can expect to get when calling them. For example, a graphics API might include functions such as DrawLine(a,b) and DrawCircle(x,y,radius).
|
The seeds of object-oriented programming might be traced back to the concept of the API (application programming interface). An API is basically a piece of paper that defines a set of subroutines and the behavior an application can expect to get when calling them.
For example, a graphics API might include functions such as DrawLine(a,b) and DrawCircle(x,y,radius). An application can make a call to DrawCircle and expect to see a circle appear on the screen. This can be a problem because different graphics hardware vendors can provide the same API. Intel, Matrox, nVidia, etc. can all provide a DrawCircle function that can be used by any application even though the internal design of the hardware and the actual code that implements the DrawCircle function is completely different. All you need to do is make sure that the software module installed on the system that provides the graphics API matches the hardware installed on the system. You can install newer and more powerful hardware later (along with newer software) and your old graphics applications will work just fine.
So how do we get from this to object-oriented programming?
The downside to APIs is that you can only have one of something. What if you had a computer with two graphics displays? You can’t use the API above as-is because it does not let you choose which display to use, and you can’t install two API libraries because the functions have the same names, and you would not be able to specify which of the two to call. The variety of technical solutions to this includes adding an “adaptor number” to each of the functions in the API. Suppose instead we invented a system function called GetNewGraphicsAPI( ) which would deliver back to us a pointer to a well-defined list of functions, such as the API described above. And suppose we added a function to the API called SelectGraphicsAdaptor(…). We could write code as shown in the “GetNewGraphics API Code” sidebar.
We can use our two pointers g1 and g2 to perform independent operations on the two graphics adaptors. Now, instead of thinking of “Pointer to list of functions,” which is a common, if somewhat complex, technique often used in ordinary “C” programming, think instead of “Object.” In fact, C++ objects are implemented internally as pointers to lists of functions. Rather than call a system function GetNewGraphicsAPI, we tweak the syntax a bit and instead write:
g1 = new GraphicsAPI( );
In this case, “new” is a new verb used by C++, which tells the system to get a new copy of the module/object I have named, in this case: GraphicsAPI.
Class vs. instance
You will hear several common terms associated with object-oriented programming. The most common and confusing are Object , Class , and Instance . Class and Instance are pretty well defined, but Object is less so. Object can refer to either a Class or an Instance. You will need to consider the context to determine how it is used in a particular case.
Consider a file. You are probably comfortable with the concept of a file. You might, for example, deal with a shift report file. You understand that a new one is created each shift and you understand the format of the data in the file, which will be different for each shift. If someone were to ask, “Does the shift report file exist or not?” You would be comfortable answering, “It depends on if the program has been run that creates the shift report file.”
A Class is a definition of an object that can be created (in the same way that the shift report can be created). Returning for a moment to the old API style of programming, it includes something analogous to the header file provided with the API, which defined the functions of the API. The difference is that the term Class also includes the code, which in the case of the API was typically provided as a software library.
Note that the code that creates the report file exists independent of whether you have actually created a report file. Similarly, the code (which implements an object’s functions, such as GraphicsAPI) and the header file (which defines the functions in that code) both exist, independent of whether or not you created an actual copy of a GraphicsAPI object.
Which brings us to the term Instance. An instance is nothing more than a real copy of an object. As soon as you say open/write/close, you have a real report file (in addition to all the code already in your system designed to handle report files). As soon as you say “new,” you have a real object (in addition to all that code designed to handle the functions associated with that object).
For more information on class and instance, see “Questions to consider about Class and Instance” sidebar.
Modular advantage
In a nutshell, the advantage of using objects is creation of faster, better, cheaper code (at least if it’s done well).
Just as well-defined APIs were a big advance over hard coding the graphics functions, objects are a big advance over APIs. They allow code to be made more modular and allow those modules to be defined more clearly and concisely. This means the code can be written faster with fewer mistakes and tested more easily. It means that new functionality can be added to the system more easily, and that it can often be done without changing the underlying system code. It means that it is generally easier to create custom interfaces and components for the system because the interfaces are more clearly defined.
Why? Extensibility, modeling Object-oriented techniques can be applied to process control on at least three levels.
First, it can and should be used by vendors in constructing their systems. As noted above, this will produce systems that are completed more quickly, are more reliable, are more easily modified and enhanced, and are easier to customize.
Second, it can be applied to the built-in extensibility often provided by scripting languages, such as Visual Basic for Applications. This allows the system integrator or end-user to program the system at the application level using object-oriented techniques. In particular, system objects, such as graphical controls (edit boxes, sliders, etc.), as well as collections of those objects (dialog boxes, controller faceplates and customized trending displays), can be created and reused. In addition, third-party graphical controls, such as ActiveX controls can be installed on the system at a later time and then added to applications and displays without actually having to modify the original system software. It’s like being able to install and use a new piece of hardware on your personal computer without having to reinstall Microsoft Windows. Such add-in controls can be used to more easily and flexibly adapt the system to user-specific needs. They give system integrators an edge by allowing them to apply the basic vendor’s system to a wider applications and to create a better fit (that is, a more effective environment) for the operators and process engineers.
Finally, object-oriented techniques can be incorporated into “process model” tools that the vendor provides. Generally, at least for day-to-day operational displays, the closer the architecture of the process control database and displays match the architecture of the actual system, the easier the system is to create, maintain, and use. Advanced control and HMI systems allow the end-user to use drag -and-drop techniques to aggregate various simple inputs and outputs (analog and digital signals) into more complex objects that represent actual process objects, such as valves and pumps. These objects can, in turn, be combined to create higher-level objects, such as a boiler, a mixer, or a dryer. Higher-level objects can be combined to create a line, building, plant site, even an entire enterprise.
Downside: tough to fix bad code
Object-oriented code, like any other form of code, can be done badly. In fact, bad object-oriented code is generally much worse than bad conventional code. If done badly it is harder to understand and can be harder to fix. And to do it well requires more training, more knowledge, more practice and probably more native ability (intelligence) than conventional code. Which means that, proportionally, the percentage or bad object code in the world is probably higher than the percentage of bad conventional code.
Object-oriented process control systems typically make use of drag-and-drop and thus produce a graphical representation of the entire system definition. Such systems look absolutely terrific during trade-show demonstrations. However, graphical database representations can be notoriously hard to navigate and maintain in practice; especially for large systems. A well-thought-out hierarchical organization can help, but still can be difficult to design and maintain. For example, connections between different layers and objects on different pages can be difficult to represent and work with graphically. Good systems will store data internally in some fairly standard format, perhaps a relational database or at least an XML file; they also will allow you to work with data either graphically or by using tables and queries.
Author Information |
Al Chisholm was a co-founder of Intellution, as well as the original architect of the OPC Data Access and OPC Alarm specifications. He is currently involved in the startup of MediaCaster Inc., targeting the remote surveillance market for the water and gas industries. |
Get NewGraphics API code
g1 = GetNewGraphicsAPI( );
g2 = GetNewGraphicsAPI( );
g1->; SelectGraphicsAdaptor(“intel”);
g2->; SelectGraphicsAdaptor(“nVidia”);
g1->;DrawCircle(50,50,25);
g2->;DrawCircle(100,100,25);
Questions to consider about Class and Instance
It is often difficult to explain the difference between Class and Instance, particularly in higher-level graphical drag and drop systems. Questions to consider include the following.
If I graphically group several valves and sensors to define a boiler, have I defined a generic reusable boiler or have I simply defined/grouped the I/O points for one particular boiler with a specific set of valves and sensors?
If I drag and drop that object somewhere else, is it a new boiler or just a second copy of the old one with links to all the same inputs and outputs?
If I have to go in and change the connections and tag names to logically hook this thing to my physical Boiler #2, how do I know which things to change?
How do I know if I have forgotten something?
What happens if I make a change to my common reusable “boiler” definition?
Do all the existing places I’ve already used it change in the same way, or do only the boilers I drag and drop in the future include the changes I made?
What if one of my boilers has a slight physical difference from the others, as is very common?
Can I tweak the instance of “boiler” associated with that physical hardware without affecting the others?
Object-oriented programming in a nutshell
Object-oriented techniques are more complex and difficult to master than conventional programming techniques.
Object-oriented techniques, when done well, allow software to be created more easily and allow that software to be more reliable and flexible.
Object-oriented techniques can be applied at all levels in process control from the vendor’s native code to the scripting provided to the user/integrator to the organization and maintenance of the actual process database and displays.
Object-oriented techniques do not, in themselves, guarantee a better result. Choose your vendors carefully, test the systems thoroughly, and make sure you understand how well the system will work in practice for your application.