Object Orientation in Ada

This is an introduction to object orientation in Ada. Ada’s inception predates the wide-spread adoption of object orientation. Like Pascal, that was extended with an object system to become Object Pascal or Lisp that was extended with flavors and eventually CLOS, Ada received an object system post-hoc with the publication of Ada 95.

Even so, Ada’s object system is fully fledged and allows multiple dispatch, inheritance, and information hiding to be done much like in languages introduced at a later time.

Interfaces

Defining an Interface

We can define interfaces in Ada by introducing an interface type along with abstract primitive operations.

type Namable is interface;

function Get_Name
  (N : Namable)
  return not null access constant String
  is abstract;

Now we have an interface Namable with a single method Get_Name.

Extending an Interface

We extend an interface by defining a new interface and merging it with another like so:

type Item is interface and Namable;

function Is_Takable
  (I : Item)
  return Boolean
  is abstract;

This gives us a new interface Item with two methods: Is_Takable and Get_Name which it inherits from its parent.

Note

is interface is sugar for is abstract tagged null record.

Classes

A class implements an interface. In Ada we define a class by deriving a new type from an interface.

In contrast to interfaces, classes host data fields.

The Ada compiler obliges us to implement all methods by overriding all abstract primitive operations of the interface.

Defining an Abstract Class

We can define an abstract class by deriving an abstract type from an interface. A class can have data fields which we push into the private section of the package. We override all methods from the interface that our abstract class implements.

type Abstract_Namable is abstract new Namable with
private;

overriding
function Get_Name
  (N : Abstract_Namable)
  return not null access constant String;

private

type Abstract_Namable is abstract new Namable with
  record
    Name        : not null access constant String;
    Description : not null access constant String;
  end record;

Defining a Concrete Class

type Simple_Item is new Abstract_Namable and Item with
private;

function Make_Item
  (Name        : not null access constant String;
   Takable     : Boolean := False)
  return Simple_Item;

overriding
function Is_Takable
  (I : Simple_Item)
  return Boolean;

private

type Simple_Item is new Abstract_Namable and Item with
  record
    Takable  : Boolean;
  end record;