Generic Packages & Formal Objects
Write generic packages that implement reusable abstract data types, use formal objects (values such as Capacity), formal subprograms, private types inside generics, per-instance state and exceptions, and understand how instantiation creates independent packages.
A generic package is a template for a whole module: a bounded stack of any element type and capacity, a queue, a matrix package for any numeric type. Each instantiation creates a new, independent package with its own types, state and exceptions. Ada's standard containers (Ada.Containers.Vectors, Hashed_Maps, ...) are generic packages of exactly this kind.
Formal Objects
Besides types and subprograms, generics accept values: 'Capacity : Positive;' is a formal object of mode in (a constant inside the instance). 'Log : in out Log_Type;' is a formal in out object that the instance can modify (a variable of the instantiating unit). Formal objects size arrays, set limits and configure behavior at instantiation time; they may have defaults ('Capacity : Positive := 100;').
• Name : T; — formal in object (a constant in the instance). • Name : in out T; — refers to a variable of the instantiator. • Defaults allowed: Capacity : Positive := 100;
Generic Packages as ADTs
The spec of Bounded_Stacks declares a private Stack type, operations and exceptions; the private part uses the formals (array (1 .. Capacity) of Element). Instantiate: 'package Int_Stacks is new Bounded_Stacks (Element => Integer, Capacity => 3, Image => Integer'Image);'. Int_Stacks.Stack and Char_Stacks.Stack are different types, and Int_Stacks.Stack_Full is different from Char_Stacks.Stack_Full. Attributes such as Integer'Image can be passed as actual subprograms. Generic packages may also be library units in their own files (bounded_stacks.ads/.adb), and generic children (generic package Parent.Child) extend generic parents.
• Each instance = separate package with its own types, state, exceptions. • Attributes (Integer'Image) can be actual subprograms. • Standard containers are generic packages.
Code Examples
Two instances of the same generic: an integer stack of capacity 3 and a character stack of capacity 5 (popping "Ada" reverses it). Integer'Image's leading space plus the separator space produces two spaces before each number. The fourth push overflows the integer stack. Output: Int stack: [ 100 200 300 ] size 3 Popped 300 -> [ 100 200 ] Char stack popped: adA Int_Stacks.Stack_Full raised (each instance has its own exceptions)
S: Bounded_Stacks.Stack; -- using the generic directly package Int_Stacks is new Bounded_Stacks (Integer, 3, Integer'Image); S: Int_Stacks.Stack;
A generic is a template; you must instantiate it before use.
when Stack_Full => -- which instance?
when Int_Stacks.Stack_Full => Each instance declares its own exceptions.
-- instantiating a generic package inside a frequently called subprogram -- instantiate once at library or package level
Instances inside subprograms are re-elaborated at each call and can't be shared.
What is 'Capacity : Positive;' in a generic formal part? A. A variable B. A formal object (value) C. A type D. A subprogram
Are Int_Stacks.Stack and Char_Stacks.Stack the same type? A. Yes B. No, each instance declares its own types C. Only if Capacity matches D. Only for private types
Can an attribute like Integer'Image be an actual for a formal function? A. Yes B. No C. Only in Ada 83 D. Only for procedures A. (verified in the example)
Which standard units are generic packages? A. Ada.Text_IO only B. Ada.Containers.Vectors, Hashed_Maps, etc. C. Ada.Calendar D. None
B. (Ada.Text_IO also contains generic children like Integer_IO) Trace the generic stack example.
Real output: Int stack: [ 100 200 300 ] size 3 Popped 300 -> [ 100 200 ] Char stack popped: adA Int_Stacks.Stack_Full raised (each instance has its own exceptions)
-- file: bounded_stacks.ads
generic
type Element is private; -- formal type
Capacity : Positive; -- formal object (a value)
with function Image (E : Element) return String; -- formal subprogram
package Bounded_Stacks is
type Stack is private;
Stack_Full, Stack_Empty : exception;
procedure Push (S : in out Stack; E : Element);
procedure Pop (S : in out Stack; E : out Element);
function Size (S : Stack) return Natural;
function Image (S : Stack) return String;
private
type Element_Array is array (1 .. Capacity) of Element;
type Stack is record
Data : Element_Array;
Top : Natural := 0;
end record;
end Bounded_Stacks;
-- file: bounded_stacks.adb
package body Bounded_Stacks is
procedure Push (S : in out Stack; E : Element) is
begin
if S.Top = Capacity then
raise Stack_Full;
end if;
S.Top := S.Top + 1;
S.Data (S.Top) := E;
end Push;
procedure Pop (S : in out Stack; E : out Element) is
begin
if S.Top = 0 then
raise Stack_Empty;
end if;
E := S.Data (S.Top);
S.Top := S.Top - 1;
end Pop;
function Size (S : Stack) retur
…