Abstract Types & Interfaces

Declare abstract tagged types and abstract subprograms, null procedures as optional hooks, interface types and multiple interface inheritance, limited/synchronized/task/protected interfaces, class-wide programming against interfaces, and the compiler checks that enforce complete implementations.

An abstract type defines a family's common structure and required operations without being instantiable itself. An interface is a pure contract with no components, and a type may implement several interfaces while inheriting from one parent. These tools let you program against capabilities (Printable, Switchable) rather than concrete types.

Abstract Types and Subprograms

'type Device is abstract tagged record ... end record;' cannot have objects; 'function Power_Watts (D : Device) return Natural is abstract;' has no body and must be overridden by every concrete descendant. The compiler enforces both rules: declaring an object of an abstract type, or deriving a concrete type without overriding an abstract operation, are compile errors. Abstract types can still have concrete components and concrete (including class-wide) operations like Summary.

• type T is abstract tagged ...; — no objects of T. • ... is abstract; — must be overridden by concrete descendants. • Abstract types can have components and concrete operations.

Interfaces

'type Printable is interface;' has no components; its primitives must be abstract or null procedures ('procedure Turn_Off (S : in out Switchable) is null;' — an optional hook with an empty default). A type can have one parent and any number of interfaces: 'type Lamp is new Device and Printable and Switchable with record ... end record;'. Parameters of type Printable'Class accept any type implementing Printable. Variants: limited interfaces, and synchronized, task and protected interfaces that tasks and protected objects can implement.

• type I is interface; — no components; abstract or null primitives. • type T is new Parent and I1 and I2 with ...; — multiple interfaces. • I'Class parameters accept any implementer. • limited / synchronized / task / protected interfaces.

Code Examples

Print and Cycle work with any Printable or Switchable object. Lamp implements both interfaces and Device's abstract Power_Watts; Sensor is only Printable. Membership tests check which interfaces a value implements. Output: Label: lamp (off) Label: lamp (on) device 1 uses 60 W device 2 uses 1 W Label: sensor Lamp in Switchable'Class? TRUE Sensor in Switchable'Class? FALSE

Two violations: Fan does not override the abstract Power, and D is an object of an abstract type. Real GNAT diagnostics: l35_err.adb:6:12: error: type must be declared abstract or "Power" overridden l35_err.adb:6:12: error: "Power" has been inherited from subprogram at line 4 l35_err.adb:9:12: error: type of object cannot be abstract type Printable is interface;... Name: String (1.. 10); -- component in an interface function Name (P: Printable) return String is abstract;

Interfaces have no components; expose data through abstract operations.

procedure Log (D: Device); -- abstract parent as a specific parameter procedure Log (D: Device'Class);

No object has the specific type Device; take Device'Class.

type Lamp is new Printable and Device with ...

type Lamp is new Device and Printable with ...

The (tagged, non-interface) parent must come first; interfaces follow with 'and'.

Can you declare an object of an abstract type? A. Yes B. No C. Only as a constant D. Only with new

B. (verified: 'type of object cannot be abstract').

How many interfaces can a tagged type implement? A. One B. Two C. Any number D. None

C. Any number (but only one parent type).

What is 'procedure Turn_Off (S : in out Switchable) is null;'? A. An error B. A null procedure — an optional operation with empty default body C. An abstract procedure D. A procedure that raises

Which interface kind can a protected type implement? A. synchronized or protected interface B. Only limited C. None D. task interface Explain the compile errors.

Real GNAT output: l35_err.adb:6:12: error: type must be declared abstract or "Power" overridden l35_err.adb:6:12: error: "Power" has been inherited from subprogram at line 4 l35_err.adb:9:12: error: type of object cannot be abstract

-- file: devices.ads
package Devices is

   --  Interfaces: no components, only (abstract or null) operations
   type Printable is interface;
   function Label (P : Printable) return String is abstract;

   type Switchable is interface;
   procedure Turn_On (S : in out Switchable) is abstract;
   procedure Turn_Off (S : in out Switchable) is null;     --  optional operation

   --  Abstract tagged type: cannot have objects of its own
   type Device is abstract tagged record
      Id : Positive;
   end record;
   function Power_Watts (D : Device) return Natural is abstract;
   function Summary (D : Device'Class) return String;       --  class-wide, concrete

   --  A concrete type derived from one abstract parent and two interfaces
   type Lamp is new Device and Printable and Switchable with record
      On : Boolean := False;
   end record;
   overriding function Power_Watts (L : Lamp) return Natural;
   overriding function Label (L : Lamp) return String;
   overriding procedure Turn_On (L : in out Lamp);
   overriding procedure Turn_Off (L : in out Lamp);

   type Sensor is new Device and Printable with null record;
   overriding function Power_Watts (S : Sensor) return Natural is
…
procedure L35_Err is
   package Devs is
      type Device is abstract tagged null record;
      function Power (D : Device) return Natural is abstract;

      type Fan is new Device with null record;   --  forgets to override Power
   end Devs;

   D : Devs.Device;                             --  object of an abstract type
begin
   null;
end L35_Err;