14 Object Oriented features of Ada

Overview

The type system of Ada that existed in Ada83 has been extended to include support for object oriented programming. Rather than an extension that would be discordant with what existed, the object oriented facilities extend the existing type system to allow for type extension. These provide all the classical object oriented facilities such as inheritance, dynamic dispatching, polymorphism, with the usual Ada features of readability and safety.
Types are for many purposes similar to classes.

The following object diagram is implemented using Ada.

Inheritance (Ada83)

Inheritance can be split into two distinct concepts, inheritance of operations (methods) and inheritance and further addition of attributes (type extension). Ada 83 supported inheritance of operations. If a new type is derived from a base type, then the derived type inherits the operations available from the parent. For example,

This model of inheritance does not allow for extension of types, that is we cannot add in extra attributes. The procedures (or functions) that take a parameter of a type are said to be the operations on the type and are equivalent to methods in other OO languages.

Inheritance (Ada95)

Ada95 has extended the notion of type derivation to support conventional object oriented programming. A new type, the tagged record, has been introduced to represent a type that can be extended (inherited). The syntax for a tagged type is

A tagged record is treated like a conventional record in most situations. Field accessing, and setting is just as normal.

Operations on the type are written just as before...

If we want to extend the type, we follow a notation similar to the type derivation common in Ada...

The "with record" part indicates the extension to the base type (in this case "person").

New operations for the manager can be added, just as in Ada83...

We may even want to override an inherited operation...

We can now write a different algortihm for pay_rise's for manager's compared to person's.

How do I set all of this up?

In Ada, the package concept is simply used for encapsulating the declaration of a type, and it's operations. The package is used to hide the implementation details, and as an aid to recompilation (we can split a program up into smaller chunks, which individually are quick to compile). A very common convention is to place one type and it's operations into one package.

The above example would thus be placed into two packages...

The declaration of the derived type would be placed in a second package...

For tagged types, the operations on the type that are included in the same package as the type declaration (as all of the above are) have a special status - they are called the primitive operations of the type - and are all potentially dispatching calls. This will be described in further detail later.

Using tagged types

Using these types is quite simple. You just declare variables as you would have before...

Null records and extensions

A type may need to be created that has no fields (attributes), only operations (methods). This can be achieved by specify an empty record when declaring a type.

Ada has a special syntax for null records being used with tagged types:

This can now be used as the basis of further derivations.

Operations on the type can be added as normal within a package specification...

More typically a new type may be derived from an existing type without the need for new attributes, but with the need for new subprograms.

The syntax for such an extension would be...

A director has no new components added, but can has yet another method for allocating a pay_rise.

Abstract types and subprograms

Sometimes we wish to create an artificial type that we never expect to use, but serves as the "root" of a tree of types. These are called abstract types. They may also include abstract subprograms , which do not have a body and must be overridden by a derived type. This forces all descendants of a type to support a common functionality.

An abstract type has the following syntax...

This implementation of a set of natural numbers is taken from the Ada Language Reference Manual. Note that you cannot declare a variable of type Set because it is an abstract type. E.g.

However a derived type may or may not be abstract...

Class wide types

For any given tagged type, there is an associated class wide type, that encompasses the tagged type and all types derived from it. Ada has used the word "class" differently to most object oriented languages. It is perhaps used in a more traditional English sense, as a collection of similar types.


For example in the type family (inheritance hierachy)

the type vehicle'class refers to all the types above. Motorised'class refers to the classes motorised, truck, car and train.

This can be used to allow for dynamic selection of the appropriate operation.

Assume that the following procedure was defined in package persons.

If we call this with a manager as a parameter, then the procedure persons.pay_rise will be called, not managers.pay_rise.

A solution to this problem is to accept as a parameter any variable in the class wide type. This is done as follows...

If the following declarations are made...

and then...

Here the pay_rise procedure called depends on the specific type passed in as a parameter. This is called dynamic dispatching - deciding which procedure to dispatchi to (or call) at run time (dynamically). Passing in a manager object results in a call to the manager's pay_rise routine. Passing in a person object results in a call to the person's pay_rise routine.
What pay_rise routine would be called if a Director object was passed in?

In fact all the primitive operations of type are potentially dispatching calls, given the right circumstances. The example using a class wide type is one example. Another (closely related) example is the use of class wide access (pointer) types.

What you can't do with a class wide type (such as person'class) is create an array of them. This is because each object is potentially a different size - arrays require all elements to be the same size. Similar considerations apply for any place where a declaration must be of a fixed size (constrained, in Ada parlance).

Class wide pointers

Most pointers in Ada are restricted to pointing at just a single type. For example...

Here variables of type ptr are restricted to always pointing at variables of type node.

With the concept of class wide types in Ada, comes the concept of a pointer that can point to any item within an inheritance hierachy.
This is achived by...

who' can now point at any object from the derivation tree rooted at person, i.e. person, manager, director, and quite importantly, any future types included in the inheritance hierachy.
For example we could make 'who' point at...

Interestingly, we could create an array of class wide access types...

Class wide pointers can be used to build hetrogeneous data structures, that is those were the components are not all the same type (they must however be in the same class).

Private tagged types

A type can be declared private to help enforce information hiding (especially of the exact details of its representation, e.g. is it an array, or a linked list?). Similarly tagged types can be made private.

The private section of the package must complete the declaration (provide what is called a full view of the type)...

A type extension can also have a private extension if desired...

This gives sufficient flexibility for most purposes.

Generic type parameters

Tagged types can now be specified as generic type parameters (they can still be passed as actuals to the normal private or limited private type parameters). The syntax is as follows...

Multiple Inheritance

Ada95 does not directly support MI. It provides features that can be used to build MI "by hand" with a bit of extra work. The options are generics (to extend a type with a set of new features), access discriminants (to allow a type to point at it's containing object, and therefore allow delegation) and another one that I can't quite remember now.


to the index...