NCL Home > Documentation > HLUs > User Guide

Understanding classes and objects

In object-oriented terminology, a class is a template for defining objects. It specifies the names and types of variables that can exist in an object, as well as "methods"--procedures for operating on those variables. A class can be thought of as a "type", with the objects being a "variable" of that type. Multiple objects, or instances of a class can be created in a single HLU program, just as you declare multiple variables of the same type in any program.

For example, the TextItem class is a template for creating an object that contains a text string. This object will have a particular set of text attributes such as font, size, and color. If we set the values of the object variables--resources--in a certain way, we can create the TextItem object "Hello World". Resources that are available for objects of the TextItem class include the text string ("Hello World" in this case), the type of font, the color of the characters, the size of the characters, the line width of the characters, etc. A TextItem object is thus an instance of the TextItem class with a set of values assigned to the associated resources. We can create a second TextItem object if we want to with a new set of resource values such as: "THIS IS ALSO A TEXTITEM OBJECT."

Class versus object

Many people get confused by the difference between class and object. The difference is simple and conceptual. A class is a template for objects. A class defines object properties including a valid range of values, and a default value. A class also describes object behavior. An object is a member or an "instance" of a class. An object has a state in which all of its properties have values that you either explicitly define or that are defined by default settings.

This subtle conceptual difference between classes and objects shows why there is a tendency to want to use them interchangeably.

Derived classes and inheritance

Sometimes it is convenient to develop a class that shares properties with another class but yet is distinct from the original. The new class derives properties from an existing class but also extends or adds its own properties. This new class is called a "derived class" and is said to "inherit" its properties and functionality from the original class.

For example, lets say the original class is a class called Box that is defined to have two properties: side length, and color. The valid values for these properties in the Box class are:

0. <= side length <= 10., default= 5.
Color is red or blue, default = red.
If we create an instance of the Box class or, in other words, an object that is in the Box class, it will have the Box class properties (side length, and color). The values of these properties will be defined as the default unless they are explicitly set.

Now let's assume we want to create a box object that is filled rather than the hollow boxes created using the Box class template. Instead of creating a completely new template that has many of the same properties of the Box class, we can derive a new class and extend the functionality of the derived class as necessary to create a class that defines filled box objects.

FilledBox will be the name of the derived class. Since it is derived from the Box class, it will automatically inherit all the properties that were in the Box class, namely side length, and color. However, in order to create boxes that are filled, we will add a new property called fill with possible values of "on" or "off" and a default value of "on." Any new objects that are created that are in the FilledBox class will be drawn as filled boxes unless the fill property is set to "off.".

Superclasses and subclasses

Another way to refer to a derived class is as a "subclass" of the original class. The class from which the subclass is derived is known as its "superclass." For example, in the HLU library the superclass of the TextItem class is the View class. The thing that all View subclasses have in common is that they can all be used to create graphical objects. Some other subclasses of the View class are XyPlot, VectorPlot, StreamlinePlot, ContourPlot, MapPlot, Title, TickMark, Legend, and LabelBar. The superclass of all subclasses is the Base class.

Often the superclasses cannot be instantiated directly. For instance, you cannot create a Base object or a View object. The role of these superclasses is to define common methods and resources that, through inheritance, are automatically available to their subclasses. For example, the non-instantiable Workstation superclass defines a resource, wkColorMap, that contains a list of currently allocated colors. Since the PSWorkstation class, used to output PostScript, is a subclass of Workstation, any PSWorkstation object can access the wkColorMap resource. In fact, all the resources defined by the Workstation class are available to a PSWorkstation object. Indeed, they are available to objects belonging to any subclass of Workstation, such as the NcgmWorkstation class or the XWorkstation class.

Mixed classes

A mixed class is another way to combine the functionality from other classes into a new class. A mixed class manages the properties of other classes and may only use a subset of the functionality of a class, whereas a derived class uses the complete set of functionality of its superclasses and usually extends this functionality.

For example, suppose that in addition to the Box class we have another class called Text. The Text class has one property, called string, with a default value of "hello world."

We could create a mixed class that would manage these two simple classes in order to produce a box object with text. We will call the new class TextBox, and, in this example, it will use all of the properties from both of the classes from which it is composed. In many cases, the mixed class may use only a subset of the properties from these classes. An object that is in the TextBox class would have the following properties: side length, color, and string.

The XyPlot class is an example of an HLU mixed class. It combines the functionality of the TickMark class and the Title class, among others. Since an XyPlot object contains both tick marks and titles (which are both available as HLU classes), it is more efficient to have the XyPlot class manage these properties rather than use its own code and properties to provide redundant functionality.

Composite classes

In the HLU library, mixed classes are known as "composite classes." In the class hierarchy chart, the boxes with a heavy outline are composite classes. For example, if you click on the box PlotManager class, you will see that it has as composite class members the Title, Legend, LabelBar, and TickMark classes. Composite classes allow access to at least a subset of the resources of their composite class members.

Composite class members can be nested. For example, since the ContourPlot class includes the PlotManager as a composite class member, all the composite class members of the PlotManager are available to the ContourPlot class. If you create a ContourPlot object, you will have access not only to the resources of the ContourPlot and its superclasses, but also to resources of the PlotManager and the PlotManager's composite class members, Title, TickMark, Legend, and LabelBar. In other words, you only have to create one object in your HLU program to have the effective functionality of a whole tree of composite class members.

User creatable objects

In a user program, only objects belonging to certain classes can be created directly. In the class hierarchy chart, the yellow boxes denote these user-instantiable classes. The other classes fall into one of four categories:
  • Non-instantiable superclasses such as Base and View
  • Classes designed to function only as composite class members, such as PlotManager and subclasses of the Transformation class
  • The classes that can have only one instance, such as Error and Workspace; they are automatically instantiated when the HLU library is initialized
  • Classes that are instantiated by certain objects for a specialized purpose on behalf of the user; these currently include the XyDataSpec and AnnoManager classes

Dynamically associated objects

In addition to the class hierarchy and composite class relationships, the HLU library has a mechanism that allows you to associate independently-created View objects dynamically. You can "overlay" Transform class objects onto a plot object's data space. You can also make any View object into an "annotation" of a plot object. The combination of the base plot object, its overlays, and its annotations acts in many ways like a single object. Plot objects, overlays, and annotations are discussed in the PlotManager class module, and also in the AnnoManager class module.

Class hierarchy versus instance hierarchy

Besides the class hierarchy of subclasses derived from the Base superclass, you should be aware that the HLU library defines an "instance hierarchy" of the objects that are created in the course of executing an HLU program. These two hierarchies are completely distinct, and you should be careful not confuse them.

Whenever you create an object, you must specify the object's "parent" as one of the parameters to the create call. Each object you create is therefore the "child" of some parent object. The initial parent, the "ancestor" of all the objects created, must be an "application" (App) object. Depending on the call used to initialize the HLU library, you may need to create this object yourself, or the library may automatically create it for you.

The instance hierarchy is significant in the following ways:

  • When you destroy a parent object all its children are destroyed along with it.
  • A View object must have a Workstation class ancestor that supplies the viewspace on which it is drawn.
  • The resource database uses the instance hierarchy to determine how resource specifications in resource files apply to particular objects in an HLU program.

See also: