Unconstrained Arrays Revisited 

v What are the benefits of using Unconstrained Arrays?

v Why do they make life easier?

 

A Deeper Step Towards Reusability

v Unconstrained Arrays allow us to use the same code for the typical operations on arrays, regardless of the length of the array.

v This is Reusability

v However, the array elements must be of the same (sub)type.

v What if we have a set of operations that we want to perform on arrays with different element types?

Generics

v For this we use Templates, called Generics in Ada.

v Swap routine:

 

PROCEDURE Swap( v1, v2 : IN OUT Natural ) IS

 temp : Natural;

BEGIN

 temp := v1;

 v1 := v2;

 v2 := temp;

END Swap;

v  

v Same routine, different type:

 

PROCEDURE Swap( v1, v2 : IN OUT Natural ) IS

 temp : Natural;

BEGIN

 temp := v1;

 v1 := v2;

 v2 := temp;

END Swap;

 

v Ada function-overloading allows us to do this.

 

v  

v This works, but could get expensive

РMore code to write

РMore code to debug

РMore code to maintain

v It would be nice if we could use the same code, and only vary the type

v Generics allow you to do this.

Generic Swap Routine

v Specification:

GENERIC

 TYPE ValueType IS PRIVATE;

PROCEDURE Swap_Gen( v1, v2 : IN OUT ValueType );

v Body:

PROCEDURE Swap_Gen( v1, v2 : IN OUT ValueType ) IS

 temp : ValueType;

BEGIN

 temp := v1;

  v1 := v2;

 v2 := temp;

END Swap_Gen;

 

WITH Swap_Gen;

É 

PROCEDURE Test_Swap_Gen IS

 X, Y : Integer;

 A, B : Character;

 

 PROCEDURE IntegerSwap IS NEW Swap_Gen(

 ValueType => Integer );

 PROCEDURE CharacterSwap IS NEW Swap_Gen(

 ValueType => Character );

 

É 

BEGIN

 X := 3; Y := 5;

 A := ÔpÕ; B := ÔqÕ;

 

 IntegerSwap( v1 => X, v2 => Y );

 É 

 CharacterSwap( v1 => A, v2 => B );

 É

END Test_Swap_Gen;

WhatÕs Happening?!

PROCEDURE Swap_Gen( v1, v2 : IN OUT ValueType ) IS

 temp : ValueType;

BEGIN

 temp := v1;

 v1 := v2;

 v2 := temp;

END Swap_Gen;

 

PROCEDURE Swap_Gen( v1, v2 : IN OUT ValueType ) IS

 temp : ValueType;

BEGIN

 temp := v1;

 v1 := v2;

 v2 := temp;

END Swap_Gen;

Operators

v Example of comparison operator:

 

FUNCTION Max( v1, v2 : Integer ) RETURN Integer IS

 Result : Integer;

BEGIN

 IF v1 > v2 THEN

 Result := v1;

 ELSE

 Result := v2;

 END IF;

 RETURN Result;

END Max;

Generic Max

v Specification:

GENERIC

 TYPE ValueType IS PRIVATE;

 WITH FUNCTION Compare( L, R : ValueType ) RETURN

 Boolean;

 

FUNCTION Max_Gen( v1, v2 : ValueType ) RETURN

 ValueType;

Generic Max Body

v Body:

FUNCTION Max_Gen( v1, v2 : ValueType ) RETURN ValueType IS

 Result : ValueType;

BEGIN

 IF Compare( v1, v2 ) THEN

 Result := v1;

 ELSE

 Result := v2;

 END IF;

 RETURN Result;

END Max_Gen;

FloatMax Example

WITH Max_Gen;

É 

PROCEDURE Test_Max_Gen IS

 X, Y, Z : Float;

 

 FUNCTION FloatMax IS NEW Max_Gen(

 ValueType => Float, Compare => Ò>Ó );

BEGIN

 X := 3.0; Y := 4.0;

 É

 Z := FloatMax( X, Y );

 É

END Test_Max_Gen;

Arrays

v This works for arrays too.

GENERIC

 TYPE ValueType IS PRIVATE;

 TYPE IndexType IS (<>);

 TYPE ArrayType IS ARRAY( IndexType RANGE <> )

 OF ValueType;

 WITH FUNCTION Compare( L, R : ValueType )

 RETURN Boolean;

 

FUNCTION Max_Array_Gen( List : ArrayType ) 

 RETURN ValueType;

 

FUNCTION Max_Array_Gen( List : ArrayType ) 

 RETURN ValueType IS

 Result : ValueType;

BEGIN

 Result := List( ListÕFirst );

 FOR Which IN ListÕRange LOOP

 IF Compare( List( Which ), Result ) THEN

 Result := List( Which );

 END IF;

 END LOOP;

RETURN Result;

END Max_Array_Gen;

 

TYPE FLoatVector IS ARRAY( Integer RANGE <> )

 OF Float;

 

FUNCTION Max IS NEW Max_Array_Gen(

 ValueType => Float, IndexType => Integer,

 ArrayType => FloatVector, Compare => Ò>Ó );