Generic units in Ada provide a powerful mechanism for creating reusable and flexible code components. They allow you to define templates for procedures, functions, packages, and other constructs that can be instantiated with different types or values. This feature is particularly useful for creating data structures and algorithms that work with any data type.

Key Concepts

  1. Generic Declaration: Defines a template with placeholders (generic parameters) that can be replaced with actual types or values when the generic unit is instantiated.
  2. Generic Instantiation: Creates a specific instance of a generic unit by providing actual parameters for the placeholders defined in the generic declaration.
  3. Generic Parameters: Can be types, subprograms, or values. They are specified in the generic declaration and replaced during instantiation.

Generic Procedures and Functions

Generic Procedure Example

Let's start with a simple example of a generic procedure that swaps two elements of any type.

generic
   type Element_Type is private;
procedure Swap(X, Y : in out Element_Type);
  • Generic Declaration: The generic keyword introduces the generic unit.
  • Generic Parameter: Element_Type is a placeholder for any type.

Implementation

procedure Swap(X, Y : in out Element_Type) is
   Temp : Element_Type;
begin
   Temp := X;
   X := Y;
   Y := Temp;
end Swap;

Instantiation

To use the generic procedure, you need to instantiate it with a specific type.

procedure Swap_Integer is new Swap(Integer);

Now, you can use Swap_Integer to swap two integers.

declare
   A, B : Integer := 10;
begin
   Swap_Integer(A, B);
   -- A is now 10, B is now 10
end;

Generic Packages

Generic packages allow you to create reusable and flexible packages. Here’s an example of a generic package for a stack data structure.

Generic Package Declaration

generic
   type Element_Type is private;
   Max_Size : Positive;
package Generic_Stack is
   procedure Push(Item : in Element_Type);
   procedure Pop(Item : out Element_Type);
   function Is_Empty return Boolean;
   function Is_Full return Boolean;
end Generic_Stack;

Implementation

package body Generic_Stack is
   type Stack_Array is array (1 .. Max_Size) of Element_Type;
   Stack : Stack_Array;
   Top : Integer := 0;

   procedure Push(Item : in Element_Type) is
   begin
      if Top < Max_Size then
         Top := Top + 1;
         Stack(Top) := Item;
      else
         raise Constraint_Error with "Stack Overflow";
      end if;
   end Push;

   procedure Pop(Item : out Element_Type) is
   begin
      if Top > 0 then
         Item := Stack(Top);
         Top := Top - 1;
      else
         raise Constraint_Error with "Stack Underflow";
      end if;
   end Pop;

   function Is_Empty return Boolean is
   begin
      return Top = 0;
   end Is_Empty;

   function Is_Full return Boolean is
   begin
      return Top = Max_Size;
   end Is_Full;
end Generic_Stack;

Instantiation

To use the generic stack package, instantiate it with a specific type and size.

package Integer_Stack is new Generic_Stack(Integer, 100);

Now, you can use Integer_Stack to create and manipulate stacks of integers.

declare
   Stack : Integer_Stack.Stack_Array;
   Item : Integer;
begin
   Integer_Stack.Push(Stack, 10);
   Integer_Stack.Push(Stack, 20);
   Integer_Stack.Pop(Stack, Item);
   -- Item is now 20
end;

Practical Exercises

Exercise 1: Generic Sorting Procedure

Create a generic procedure for sorting an array of any type.

Solution

generic
   type Element_Type is private;
   type Array_Type is array (Positive range <>) of Element_Type;
   with function "<" (Left, Right : Element_Type) return Boolean;
procedure Generic_Sort(A : in out Array_Type);

procedure Generic_Sort(A : in out Array_Type) is
begin
   for I in A'First .. A'Last - 1 loop
      for J in I + 1 .. A'Last loop
         if A(J) < A(I) then
            declare
               Temp : Element_Type := A(I);
            begin
               A(I) := A(J);
               A(J) := Temp;
            end;
         end if;
      end loop;
   end loop;
end Generic_Sort;

Exercise 2: Instantiate and Use the Generic Sorting Procedure

Instantiate the generic sorting procedure for an array of integers and sort an array.

Solution

procedure Sort_Integer_Array is new Generic_Sort(Integer, Integer_Array, "<");

declare
   A : Integer_Array(1 .. 5) := (5, 3, 4, 1, 2);
begin
   Sort_Integer_Array(A);
   -- A is now (1, 2, 3, 4, 5)
end;

Summary

In this section, you learned about generic units in Ada, including generic procedures, functions, and packages. You saw how to declare, implement, and instantiate generic units, and you practiced creating and using a generic sorting procedure. Understanding generics is crucial for writing reusable and flexible code in Ada, and it prepares you for more advanced topics in the language.

© Copyright 2024. All rights reserved