5.2 Generic programming in Ada.

We will begin our tour of Ada's generic programming facilities with an Ada generic subprogram which encapsulates the sort example.

Example - Bubble_Sort.ads

This specification shows us many of the features of Ada generics. For example note that we have said quite a few things about what we are going to sort, it is an array, for which we don't know the bounds (so it is specified as range <>), we also can't expect that the range of the array is an integer range and so we must also make the range type a parameter, Index_Type. Then we come onto the element type, this is simply specified as private, so all we know is that we can test equality and assign one to another. This provides us complete type safety, we know the type, bounds and size of the array and its components, better than C++ can provide us.

Ada must also have a function to compare two elements, similar to the C++ example 5.3 above. However in this case we will ask for the function (notice the use of the keyword with) which, although it looks like an operator, can be any function which matches the signature.

You should already be able to see the difference between the Ada code and C code as far as readability (and therefore maintainability) and safety are concerned and why, therefore, Ada promotes the reuse philosophy.

The Ada Bubble_Sort specification may look a little daunting, somewhat large and possibly complex. However type-independent programming is difficult in a type safe language and so generics have to be rigorous in their specification of what types are allowed and how they are to be used.

We can now look at how we might implement the sort algorithm itself.

Example - Bubble_Sort.adb

Note the use of the scalar and discrete attributes to calculate the bounds of the array in a type safe and truly generic manner (for instance the use of Index_Type'Succ(Item) instead of the more usual C code [Item + 1]). Also we compare two array elements in the central if statement using the passed ">" function, just as we might in C++ if we have provided the type Element_Type with an overloaded operator, in the Ada code it is not treated as an operator call, simply a call to the provided function.

We can now use our generic to sort a nice simple array of integers, using the supplied comparison operator.

Example - Sort_Test1.adb

The first two types simply declare the type of the array index, in this case a subtype of Positive, and an array we are going to sort.

We then instantiate the generic with the parameters required, the array index type, the type of the array component, the type of the array and finally the comparison function (in this case the primitive operator for type Integer). Of course we then declare an array and sort it and print the array; just in case.

In comparison to C++ we must explicitly instantiate each and every use of a generic subprogram before use. In C++ templated functions are automatically instantiated where they are used, taking their type parameters from the parameters used at the call site. The explicit instantiation is important in Ada as it follows the static typing principles and therefore provides very explicit compile time type checking

Some C programmers may be looking at the first example and saying to themselves that because you must specify the bounds of the array by hand it is actually more flexible, you can specify a bound smaller than the overall array to sort only part of it like this:

int test_array[10];

sort(test_array, 8); /* sort only first 8 */
sort(&test_array[1], 8); /* sort 1 .. 9 */

Where the second example is quite interesting, we have sorted a slice of the array, which is exactly what we would consider doing in the Ada examples above.

declare
   ..
   Sort_This : An_Array(0 .. 9);
begin
   Test_Sort(Sort_This(0 .. 7));

   Test_Sort(Sort_This(1 .. 8));

However what is the result of the following code in the respective languages?

int test_array[10];

sort(test_array, 11); /* possible crash! */

declare
   ..
   Sort_This : An_Array(0 .. 9);
begin
   Test_Sort(Sort_This(0 .. 11)); -- compiler error

Example - Sort_Test2.adb

We have now use the same sort function on a more realistic example. The important thing to note in this example is that in each instance of the generic the formal parameter "<" has been replaced with a function which compares a single component of the structure, therefore two different sorting methods can be achieved with the same sort algorithm.

It is even possible to reverse sort the array by passing an operator ">" where the operator "<" is expected, when the generic is instantiated only the signature of the passed subprogram is checked and both < and > have the same signature just different results.


Previous PageContents PageNext Page

Copyright © 1996 Simon Johnston &
Addison Wesley Longman