G.T. Generic Types - JulTob/Ada GitHub Wiki

Ada's generic facilities allow you to specify constraints on the operations that must be supported by the types used to instantiate the generic. This capability is critical for ensuring that the generic unit operates correctly with the types it's given, while still allowing flexibility in what those types can be.

Generic Type Definitions in Ada

When defining a generic type in Ada, you can specify various kinds of constraints or assumptions about the operations that the type supports. This helps to enforce that the type provided when instantiating the generic has the necessary capabilities (like assignment, comparison, or specific mathematical operations). Here are the most common forms:

Private Types

These require the least amount of knowledge about the operations on the type, mainly that it supports assignment (:=).

type Item is private;
  -- Supports:  := 

Limited Private Types

These types are similar to private types but do not even assume assignability. This is useful for types that manage resources or have other constraints where copying isn't allowed.

type Item is limited private;

Interface Types

You can specify that a type must implement a certain interface, which can include any number of operations. This is more common in object-oriented programming within Ada.

type Interface_Type is interface;
type Item is new Interface_Type with private;

with Clauses for Operations

You can specify that the generic type must support certain operations, such as comparison operators or specific functions. This is often used for types where sorting or other algorithmic manipulations are necessary.

generic
   type Element_Type is private;
   with function "=" (Left, Right : Element_Type) return Boolean is <>;
procedure Process_Elements;

Here, Element_Type must support the equality operation =, which is needed within the Process_Elements procedure.

Deriving from Specific Types

If you want to ensure that the type supports certain operations inherent to a predefined or previously defined type, you can require that the generic type derive from that base type.

type Base_Type is tagged private;
type Derived_Type is new Base_Type with private;

Example: Specifying a Generic Type with a Required Operation

generic
   type Item is private;
   with function "<" (Left, Right : Item) return Boolean is <>;

   package Generic_Stack is
      procedure Push(Item : in Item);
      function Pop return Item;
      function Is_Empty return Boolean;
      -- Additional stack operations
      end Generic_Stack;
  • Generic Constraint
    • The generic package Generic_Stack requires that any Item type used to instantiate it must have a less-than operator defined (<). This could be used within the package to maintain a sorted stack, for example.
  • Flexibility and Safety
    • This approach maintains flexibility—any type with the required operations can be used—while ensuring type safety by enforcing the necessary operations at compile time.

Ada’s generic system is highly powerful and can enforce a wide range of constraints on types, ensuring that generics are both flexible and safe to use across different contexts and applications. This feature is part of what makes Ada particularly strong in domains requiring high reliability, such as aerospace, defense, and safety-critical systems.