Generic Procedures and Functions
Generic Procedures (and Functions)
The Problem
- Useful to be able to parameterize procedures and functions as well as packages
- Example: Sort procedure that can be instantiated for any desired type
- Goal is to maintain flexibility along with strong typing
- Solution: Generic Procedures and Functions
Generic Procedures
- Ada also has generic procedures.
- A generic procedure operates like a cookie cutter procedure: it allows types and other procedures
to be used in creating procedures that operate on those types
Example Generic Procedure: Swap
- Specification - generic_swap.ads :
generic
type ItemType is private;
procedure generic_swap(left, right: in out ItemType);
Body - generic_swap.adb :
procedure generic_swap(left, right : in out ItemType) is
old_left : constant ItemType := left;
begin
left := right;
right := old_left;
end generic_swap;
Client:
with generic_swap;
procedure use_swaps is
type color is (red, blue, green);
procedure swap_int is new generic_swap(ItemType => Integer);
procedure swap_color is new generic_swap(ItemType => Color);
procedure swap is new generic_swap(ItemType => Float);
procedure swap is new generic_swap(ItemType => Character);
i, j: Integer;
c, d: Color;
f, g: Float;
x, y: Character;
begin
-- Do some stuff
swap_int(i, j);
swap_color(c, d);
swap(f, g);
swap(x, y);
Can be used for reference and primitive types
Example Generic Procedures: Sort
- Example: A sort routine that will sort any type object
- Problem: How does sort know how to compare "any type of object"?
- Solution: ...
- Generic Procedure Specification - generic_sort.ads :
generic
type ItemType is private;
type Index_Type is (<>); -- Any discrete type
type Array_Type is array (Index_Type range <>) of ItemType;
with function "<"(X, Y: ItemType)
return Boolean is <>; -- Use default if not specified
procedure generic_sort(A: Array_Type);
Generic Procedure Body - generic_sort.adb:
procedure generic_sort(A: Array_Type) is
-- implementation goes here
end generic_sort;
Client
with generic_sort;
procedure use_sorts is
type MyArray is array (Natural range <>) of Character;
procedure sort1 is new generic_sort(
ItemType => Character,
Index_Type => Natural;
Array_Type => MyArray -- Uses default less than for characters
);
type YourArray is array (Natural range <>) of Integer;
procedure sort2 is new generic_sort(
ItemType => Integer,
Index_Type => Natural;
Array_Type => YourArray;
"<" => "<"; -- Use the built in less than for integers
);
type Individual is record
a, b: natural;
end record;
type IndividualArray is array (Natural range <>) of Individual;
function less(i, j: Individual) return boolean is
(i.a < i.b);
procedure sort3 is new generic_sort(
ItemType => Individual,
Index_Type => Natural;
Array_Type => IndividualArray;
"<" => less;
);
ma: MyArray(1..10)
ya: YourArray(1..10)
ia: IndividualArray(1..10)
begin
-- Fill the arrays
sort1(ma)
sort2(ya)
sort3(ia)
Library Generic Sort Procedure
with Ada.Containers.Generic_Array_Sort;
with Ada.Containers.Generic_Constrained_Array_Sort;
procedure gsort is
type Individual is record
a, b: natural;
end record;
function less(i, j: Individual) return boolean is
(i.a < j.a);
subtype pop_range is natural range 1 .. 10;
-- CONSTRAINED TYPE
type population is array(pop_range) of individual;
procedure c_sort is new Ada.Containers.Generic_Constrained_Array_Sort(
Index_Type => pop_range,
Element_Type => individual,
Array_Type => population);
-- By default, uses the above function less for Individuals
-- UNCONSTRAINED TYPE
type upopulation is array(pop_range range <>) of individual;
procedure u_sort is new Ada.Containers.Generic_Array_Sort(
index_type => pop_range,
array_type => upopulation,
element_type=>individual,
"<" => less);
pop: population := (others => (0, 0));
upop: upopulation(1 .. 10) := (others => (0, 0));
begin
c_sort(pop);
u_sort(upop);
end gsort;
Generic Procedures and Functions: More Examples
- Other generic procedures and functions:
- Ada.Unchecked_Conversion - copies one bitstring into another, ignoring types!
(specification)
with Ada.Unchecked_Conversion;
...
function float_to_int is new Ada.Unchecked_Conversion (
Source => Float,
Target => Integer
);
f : Float := 1.0;
i : Integer := float_to_int (f);
begin
put (f, 1, 1, 0);
put (i);
put (i, base => 16);
put (i, base => 2);
-- 1.0 1065353216 16#3F800000# 2#1111 1110 0000 0000 0000 0000 0000 00#
...
unchecked_deallocation - deallocates objects on the heap
(specification)
procedure free is new Ada.Unchecked_Deallocation (
Object => Node,
Name => Node_Pointer
);
p: Node_Pointer;
...
p := new Node; -- Allocate a new node on the heap
...
free(p); -- Deallocate the node where p points