Menu:

Design and Sell Merchandise Online for Free

Abstract types

This tutorial will show you what an abstract type is in Ada. I will also provide information on how the Ada type equates to the C++ class.

An abstract type provides the "specification" for a family of a user defined types. When this type is derived from, the programmer must specify the operations that are defined as abstract.

Say we have a simple vehicle which can change gears, accelerate and brake. We're not interested in knowing what speed we're going, just the basics. In C++ a Vehicle pure virtual class could be defined:

C++ code
class Vehicle {
    virtual bool GearUp() = 0;
    virtual bool GearDown() = 0;
    virtual void Accelerate() = 0;
    virtual void Brake() = 0;
};

This can then be derived from to create a number of concrete vehicles:

C++ code
class Car : public Vehicle {
    bool GearUp();
    bool GearDown();
    void Accelerate();
    void Brake();
};

bool Car::GearUp() {
    // Change the car's gears.
}

// etc.

class Van : public Vehicle {
    bool GearUp();
    bool GearDown();
    void Accelerate();
    void Brake();
};

bool Van::GearUp() {
    // Change the van's gears.
}

// etc.

class Scooter : public Vehicle {
    bool GearUp();
    bool GearDown();
    void Accelerate();
    void Brake();
};

bool Scooter::GearUp() {
    // Change the scooter's gears.
}

// etc.

Now, in Ada95 we use an abstract tagged type to implement the Vehicle type:

Ada95 code
package Vehicle is
  
  type Vehicle_Type is abstract tagged private;

  function Gear_Up(
    Self : Vehicle_Type) return Boolean is abstract;
  function Gear_Down(
    Self : Vehicle_Type) return Boolean is abstract;
  procedure Accelerate(Self : Vehicle_Type) is abstract;
  procedure Brake(Self : Vehicle_Type) is abstract;

private

  type Vehicle_Type is abstract tagged null record;

end Vehicle;

Notice how the package has no body, it is a specification only and all operations are abstract, which means that any types which derive from this one must provide implementations of all the primitive operations.

Again, this can then be derived from to create a number of concrete vehicles:

Ada95 code
with Vehicle;

package Car is
  
  type Car_Type is new Vehicle.Vehicle_Type with private;

  function Gear_Up(Self : Car_Type) return Boolean;
  function Gear_Down(Self : Car_Type) return Boolean;
  procedure Accelerate(Self : Car_Type);
  procedure Brake(Self : Car_Type);

private

  type Car_Type is new Vehicle.Vehicle_Type with
    null record;

end Car;

package body Car is
  
  function Gear_Up(Self : Car_Type) return Boolean is

  begin

    -- Change the car's gears.

  end Gear_Up;

  -- Etc.

end Car;

with Vehicle;

package Van is
  
  type Van_Type is new Vehicle.Vehicle_Type with private;

  function Gear_Up(Self : Van_Type) return Boolean;
  function Gear_Down(Self : Van_Type) return Boolean;
  procedure Accelerate(Self : Van_Type);
  procedure Brake(Self : Van_Type);

private

  type Van_Type is new Vehicle.Vehicle_Type with
    null record;

end Van;

package body Van is
  
  function Gear_Up(Self : Van_Type) return Boolean is

  begin

    -- Change the van's gears.

  end Gear_Up;

  -- Etc.

end Van;

with Vehicle;

package Scooter is
  
  type Scooter_Type is new Vehicle.Vehicle_Type with
    private;

  function Gear_Up(Self : Scooter_Type) return Boolean;
  function Gear_Down(Self : Scooter_Type) return Boolean;
  procedure Accelerate(Self : Scooter_Type);
  procedure Brake(Self : Scooter_Type);

private

  type Scooter_Type is new Vehicle.Vehicle_Type with
    null record;

end Scooter;

package body Scooter is
  
  function Gear_Up(Self : Scooter_Type) return Boolean is

  begin

    -- Change the scooter's gears.

  end Gear_Up;

  -- Etc.

end Scooter;

So, where ever a pointer to a Vehicle type is used it is possible to assign either Car, Van or Scooter instance to that variable:

Ada95 code
with Vehicle;
with Car;
with Scooter;
with Van;

procedure Test is

  -- Make sure we can accept pointers to all vehicles
  -- in this class.
  type Vehicle_Access is access all
    Vehicle.Vehicle_Type'Class;

  A      : Vehicle_Access;
  C      : aliased Car.Car_Type;
  S      : aliased Scooter.Scooter_Type;
  V      : aliased Van.Van_Type;
  Result : Boolean;

begin

  -- Call's Car.Gear_Up
  A      := C'Access;
  Result := Vehicle.Gear_Up(A.all);

  -- Call's Scooter.Gear_Up
  A      := S'Access;
  Result := Vehicle.Gear_Up(A.all);

  -- Call's Van.Gear_Up
  A      := V'Access;
  Result := Vehicle.Gear_Up(A.all);

end Test;

I have placed a full example into a compressed text file which can be built with GNAT using the following commands:

Bash code
$ gunzip abstract_types.ada.gz
$ gnatchop -cw abstract_types.ada
$ gnatmake test.adb

Other Ada95 compilers will differ.

Download abstract_types.ada.gz

Luke
Comment
Re: Defining an interface to a family of types
Reply #2 on : Sat September 22, 2007, 16:19:45
Ah, cut n paste errors ;D
Anh Vo
Comment
Abstract Types
Reply #1 on : Fri September 14, 2007, 22:51:10
It is a simple but nice example showing the equivalence of Ada and C++. By the way, there is a missing semicolon at the forward declaration of void Accelerate() in C++ codes.

Write a comment

  • Required fields are marked with *.

If you have trouble reading the code, click on the code itself to generate a new random code.
Security Code: *