Chapter 7: Generics in ADA Programming Language

Ada’s generics provide a mechanism for code reuse while maintaining strong type-checking. They allow the definition of abstract templates that can be instantiated later with specific types. Generics are a central feature of Ada programming language and can greatly improve the maintainability and reliability of your code by allowing the same logic to be safely applied to different data types.

Understanding Generics in ADA Programming Language

To understand generics, you can think of them as a kind of code template or blueprint. A generic piece of code outlines a structure that can be filled in with specific types or values upon instantiation. Generics are checked for correctness when they are instantiated, not when they are defined. This means that if you write a generic and then instantiate it with a certain type, the compiler ensures that the generic code is applicable to that type.

Consider a basic operation like swapping the values of two variables. With generics, you can write a single swapping procedure that can swap two integers, two floats, two strings, or two variables of any other type.

Here’s a simple example of a generic procedure:

generic
   type T is private;
procedure Swap(X, Y : in out T);

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

In this example, T is a generic type. When you instantiate this procedure, you provide a specific type in place of T.

Here’s how you could instantiate it:

procedure Swap_Int is new Swap(Integer);
procedure Swap_Float is new Swap(Float);
procedure Swap_String is new Swap(String);

Now, Swap_Int, Swap_Float, and Swap_String are all procedures that can swap two integers, two floats, and two strings, respectively.

Generics in Ada allow you to write code that is type-safe, reusable, and efficient, making them a powerful tool for a variety of programming tasks. Especially in complex domains like aerospace software, where you often deal with different types of data, generics can be very beneficial for organizing your code and reducing duplication.

Generic Subprograms and Packages

Generics in Ada can be applied to both subprograms (procedures and functions) and packages, allowing a high degree of reusability and type safety in your code.

Generic Subprograms

Generic subprograms can be procedures or functions. The declaration of a generic subprogram begins with the keyword generic, followed by one or more generic formal parameters, which can represent types, objects, or other subprograms.

Here’s an example of a generic procedure:

generic
   type T is private;
procedure Print_Array(A : array (Integer range <>) of T);

procedure Print_Array(A : array (Integer range <>) of T) is
begin
   for I in A'Range loop
      Ada.Text_IO.Put(Item => A(I)'Image);
   end loop;
   Ada.Text_IO.New_Line;
end Print_Array;

In this example, Print_Array is a generic procedure that can print the elements of an array of any type.

Generic Packages

Generic packages, on the other hand, can include generic subprograms, but also types, variables, or even other packages. The declaration of a generic package is also introduced by the generic keyword and a list of formal parameters.

Here’s an example of a generic package:

generic
   type Element_Type is private;
   Max : Positive;
package Stack is
   type Stack_Type is private;
   
   procedure Push(S : in out Stack_Type; E : Element_Type);
   function Pop(S : in out Stack_Type) return Element_Type;
   function Is_Empty(S : Stack_Type) return Boolean;
private
   type Stack_Array is array (1..Max) of Element_Type;
   type Stack_Type is record
      Data : Stack_Array;
      Top : Integer := 0;
   end record;
end Stack;

In this example, Stack is a generic package that provides an implementation of a stack data structure. The stack can hold elements of any type, and its maximum size is specified when the package is instantiated.

The power of generics in Ada really shines when it comes to complex applications like aerospace software, where the same logic often needs to be applied to different types or where you need to ensure the strong type safety that Ada provides. Generics can help make your software more reliable, maintainable, and efficient.

Practical Examples of Generics in Ada Programming Language

Now that we have a good understanding of the concepts and mechanisms of generics, let’s see how they can be applied in practical situations in aerospace software development.

Let’s consider a scenario in aerospace software where we need a generic sort function that can sort arrays of different types. A common sorting algorithm is the bubble sort.

Here is a generic bubble sort function in Ada:

generic
   type T is private;
   with function "<"(Left, Right : T) return Boolean is <>;
procedure Generic_Bubble_Sort(Items : in out Array_Type);

procedure Generic_Bubble_Sort(Items : in out Array_Type) is
   Temp : T;
begin
   for I in Items'First..Items'Last loop
      for J in I+1..Items'Last loop
         if Items(J) < Items(I) then
            Temp := Items(I);
            Items(I) := Items(J);
            Items(J) := Temp;
         end if;
      end loop;
   end loop;
end Generic_Bubble_Sort;

You can now instantiate this generic procedure for different types as needed.

In the context of aerospace, you could use this function to sort arrays of different types of data that your software might need to handle. For instance, you might need to sort an array of flight times, altitudes, or speeds.

procedure Bubble_Sort_Float is new Generic_Bubble_Sort(Float);
procedure Bubble_Sort_Int is new Generic_Bubble_Sort(Integer);

Remember that Ada checks the correctness of generics at the point of instantiation, meaning that it ensures the logic of your generic sort function is applicable to the type you instantiate it with. This ensures type safety and reduces the chance of runtime errors.

Generics are an incredibly powerful feature of Ada, enabling you to write reusable and type-safe code. Especially in complex systems like aerospace software, where you need to work with different types of data and ensure the high reliability of your code, generics can be very beneficial.

Let’s see another example code.

Let’s create a generic package in Ada for a Flight Management System (FMS) that deals with waypoints. A waypoint is a reference point in physical space used for purposes of navigation. For our example, we will have two types of waypoints – one for land (denoting airports) and one for air (denoting navigational beacons).

We’ll define a generic package Waypoint_Handler that can handle any type of waypoint. This package will have a procedure Print_Waypoints to print details of all waypoints and a function Calculate_Distance to calculate the distance between two waypoints. For simplicity, the distance calculation is a placeholder and does not actually calculate geographical distance.

generic
   type Waypoint is limited private;
   with function Get_Name(W : Waypoint) return String is <>;
   with function Get_Coordinates(W : Waypoint) return String is <>;
package Waypoint_Handler is
   type Waypoints is array (Integer range <>) of Waypoint;

   procedure Print_Waypoints(W : Waypoints);
   function Calculate_Distance(W1, W2 : Waypoint) return Float;
end Waypoint_Handler;

Now, the implementation of Waypoint_Handler:

package body Waypoint_Handler is
   procedure Print_Waypoints(W : Waypoints) is
   begin
      for I in W'Range loop
         Ada.Text_IO.Put_Line("Name: " & Get_Name(W(I)) & ", Coordinates: " & Get_Coordinates(W(I)));
      end loop;
   end Print_Waypoints;

   function Calculate_Distance(W1, W2 : Waypoint) return Float is
   begin
      -- Placeholder for actual distance calculation
      return 0.0;
   end Calculate_Distance;
end Waypoint_Handler;

Next, let’s define two specific waypoint types Land_Waypoint and Air_Waypoint:

type Land_Waypoint is private;
type Air_Waypoint is private;

private
   type Land_Waypoint is
      record
         Name : String (1..10);
         Coordinates : String (1..10);
      end record;

   type Air_Waypoint is
      record
         Name : String (1..10);
         Coordinates : String (1..10);
      end record;

Now, we can instantiate the Waypoint_Handler for these types:

function Get_Name(W : Land_Waypoint) return String is (W.Name);
function Get_Coordinates(W : Land_Waypoint) return String is (W.Coordinates);
package Land_Waypoint_Handler is new Waypoint_Handler(Land_Waypoint, Get_Name, Get_Coordinates);

function Get_Name(W : Air_Waypoint) return String is (W.Name);
function Get_Coordinates(W : Air_Waypoint) return String is (W.Coordinates);
package Air_Waypoint_Handler is new Waypoint_Handler(Air_Waypoint, Get_Name, Get_Coordinates);

With these packages, we now have a generic way of handling any type of waypoint in our FMS, demonstrating the power and flexibility of generics in Ada for aerospace software.

Chapter 7: Generics in ADA Programming Language
Scroll to top
error: Content is protected !!