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 => Ò>Ó );