diff --git a/courses/fundamentals_of_ada/160_genericity-intro.rst b/courses/fundamentals_of_ada/160_genericity-intro.rst new file mode 100644 index 000000000..a4f4785bd --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity-intro.rst @@ -0,0 +1,40 @@ +************ +Genericity +************ + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 160_genericity/01-introduction.rst +.. include:: 160_genericity/02-creating_generics.rst +.. include:: 160_genericity/03-generic_data.rst +.. include:: 160_genericity/04-generic_formal_data.rst +.. include:: 160_genericity/99-summary.rst diff --git a/courses/fundamentals_of_ada/160_genericity.rst b/courses/fundamentals_of_ada/160_genericity.rst index d7eac0b1f..9a27b617b 100644 --- a/courses/fundamentals_of_ada/160_genericity.rst +++ b/courses/fundamentals_of_ada/160_genericity.rst @@ -1,630 +1,42 @@ -************ -Genericity -************ - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - -------------------------- -The Notion of a Pattern -------------------------- - -* Sometimes algorithms can be abstracted from types and subprograms - - .. code:: Ada - - procedure Swap_Int (Left, Right : in out Integer) is - V : Integer := Left; - begin - Left := Right; - Right := V; - end Swap_Int; - - procedure Swap_Bool (Left, Right : in out Boolean) is - V : Boolean := Left; - begin - Left := Right; - Right := V; - end Swap_Bool; - -* It would be nice to extract these properties in some common pattern, and then just replace the parts that need to be replaced - - .. code:: Ada - - procedure Swap (Left, Right : in out (Integer | Boolean)) is - V : (Integer | Boolean) := Left; - begin - Left := Right; - Right := V; - end Swap; - --------------------- -Solution: Generics --------------------- - -* A :dfn:`generic unit` is a unit that does not exist -* It is a pattern based on properties -* The instantiation applies the pattern to certain parameters - --------------------------------------- -Ada Generic Compared to C++ Template --------------------------------------- - -.. container:: columns - - .. container:: column - - Ada Generic - - .. container:: latex_environment scriptsize - - .. code:: Ada - - -- specification - generic - type T is private; - procedure Swap (L, R : in out T); - - -- implementation - procedure Swap (L, R : in out T) is - Tmp : T := L; - begin - L := R; - R := Tmp; - end Swap; - - -- instance - procedure Swap_F is new Swap (Float); - - .. container:: column - - C++ Template - - .. container:: latex_environment scriptsize - - .. code:: C++ - - // prototype - template - void Swap (T & L, T & R); - - // implementation - template - void Swap (T & L, T & R) { - T Tmp = L; - L = R; - R = Tmp; - } - - // instance - int x, y; - Swap(x,y); - -=================== -Creating Generics -=================== - ---------------------------- -What Can Be Made Generic? ---------------------------- - -* Subprograms and packages can be made generic - - .. code:: Ada - - generic - type T is private; - procedure Swap (L, R : in out T) - generic - type T is private; - package Stack is - procedure Push (Item : T); - ... - -* Children of generic units have to be generic themselves - - .. code:: Ada - - generic - package Stack.Utilities is - procedure Print (S : Stack_T); - ---------------------------- -How Do You Use a Generic? ---------------------------- - -* Generic instantiation is creating new set of data where a generic package contains library-level variables: - -.. code:: Ada - - package Integer_Stack is new Stack (Integer); - package Integer_Stack_Utils is - new Integer_Stack.Utilities; - ... - Integer_Stack.Push (S, 1); - Integer_Stack_Utils.Print (S); - -============== -Generic Data -============== - --------------------------------- -Generic Types Parameters (1/3) --------------------------------- - -* A generic parameter is a template -* It specifies the properties the generic body can rely on - - .. code:: Ada - - generic - type T1 is private; - type T2 (<>) is private; - type T3 is limited private; - package Parent is - -* The actual parameter must be no more restrictive then the :dfn:`generic contract` - ---------------------------------------- -Generic Types Parameters (2/3) ---------------------------------------- - -* Generic formal parameter tells generic what it is allowed to do with the type - -.. container:: latex_environment tiny - - .. list-table:: - - * - :ada:`type T1 is (<>);` - - - Discrete type; :ada:`'First`, :ada:`'Succ`, etc available - - * - :ada:`type T2 is range <>;` - - - Signed Integer type; appropriate mathematic operations allowed - - * - :ada:`type T3 is digits <>;` - - - Floating point type; appropriate mathematic operations allowed - - * - :ada:`type T4;` - - - Incomplete type; can only be used as target of :ada:`access` - - * - :ada:`type T5 is tagged private;` - - - :ada:`tagged` type; can extend the type - - * - :ada:`type T6 is private;` - - - No knowledge about the type other than assignment, comparison, object creation allowed - - * - :ada:`type T7 (<>) is private;` - - - :ada:`(<>)` indicates type can be unconstrained, so any object has to be initialized - --------------------------------- -Generic Types Parameters (3/3) --------------------------------- - -* The usage in the generic has to follow the contract - - * Generic Subprogram - - .. code:: Ada - - generic - type T (<>) is private; - procedure P (V : T); - procedure P (V : T) is - X1 : T := V; -- OK, can constrain by initialization - X2 : T; -- Compilation error, no constraint to this - begin - - * Instantiations - - .. code:: Ada - - type Limited_T is limited null record; - - -- unconstrained types are accepted - procedure P1 is new P (String); - - -- type is already constrained - -- (but generic will still always initialize objects) - procedure P2 is new P (Integer); - - -- Illegal: the type can't be limited because the generic - -- thinks it can make copies - procedure P3 is new P (Limited_T); - ------------------------------------- -Generic Parameters Can Be Combined ------------------------------------- - -* Consistency is checked at compile-time - -.. code:: Ada - - generic - type T (<>) is private; - type Acc is access all T; - type Index is (<>); - type Arr is array (Index range <>) of Acc; - function Element (Source : Arr; - Position : Index) - return T; - - type String_Ptr is access all String; - type String_Array is array (Integer range <>) - of String_Ptr; - - function String_Element is new Element - (T => String, - Acc => String_Ptr, - Index => Integer, - Arr => String_Array); - ------- -Quiz ------- - -.. code:: Ada - - generic - type T1 is (<>); - type T2 (<>) is private; - procedure G - (A : T1; - B : T2); - -Which is (are) legal instantiation(s)? - - A. ``procedure A is new G (String, Character);`` - B. :answermono:`procedure B is new G (Character, Integer);` - C. :answermono:`procedure C is new G (Integer, Boolean);` - D. :answermono:`procedure D is new G (Boolean, String);` - -.. container:: animate - - :ada:`T1` must be discrete - so an integer or an enumeration. :ada:`T2` can be any type - -===================== -Generic Formal Data -===================== - --------------------------------------------- -Generic Constants/Variables As Parameters --------------------------------------------- - -.. container:: columns - - .. container:: column - - * Variables can be specified on the generic contract - * The mode specifies the way the variable can be used: - - - :ada:`in` |rightarrow| read only - - :ada:`in out` |rightarrow| read write - - * Generic variables can be defined after generic types - - .. container:: column - - .. container:: latex_environment tiny - - * Generic package - - .. code:: Ada - - generic - type Element_T is private; - Array_Size : Positive; - High_Watermark : in out Element_T; - package Repository is - - * Generic instance - - .. code:: Ada - - V : Float; - Max : Float; - - procedure My_Repository is new Repository - (Element_T => Float, - Array_size => 10, - High_Watermark => Max); - -------------------------------- -Generic Subprogram Parameters -------------------------------- - -* Subprograms can be defined in the generic contract -* Must be introduced by :ada:`with` to differ from the generic unit - - .. code:: Ada - - generic - type T is private; - with function Less_Than (L, R : T) return Boolean; - function Max (L, R : T) return T; - - function Max (L, R : T) return T is - begin - if Less_Than (L, R) then - return R; - else - return L; - end if; - end Max; - - type Something_T is null record; - function Less_Than (L, R : Something_T) return Boolean; - procedure My_Max is new Max (Something_T, Less_Than); - ----------------------------------------- -Generic Subprogram Parameters Defaults ----------------------------------------- - -* :ada:`is <>` - matching subprogram is taken by default -* :ada:`is null` - null procedure is taken by default - - - Only available in Ada 2005 and later - - .. code:: Ada - - generic - type T is private; - with function Is_Valid (P : T) return Boolean is <>; - with procedure Error_Message (P : T) is null; - procedure Validate (P : T); - - function Is_Valid_Record (P : Record_T) return Boolean; - - procedure My_Validate is new Validate (Record_T, - Is_Valid_Record); - -- Is_Valid maps to Is_Valid_Record - -- Error_Message maps to a null procedure - -.. - language_version 2005 - ------- -Quiz ------- - -.. include:: quiz/genericity_type_and_variable/quiz.rst - ------- -Quiz ------- - -.. container:: columns - - .. container:: column - - - .. code:: Ada - :number-lines: 1 - - procedure Double (X : in out Integer); - procedure Square (X : in out Integer); - procedure Half (X : in out Integer); - generic - with procedure Double (X : in out Integer) is <>; - with procedure Square (X : in out Integer) is null; - procedure Math (P : in out Integer); - procedure Math (P : in out Integer) is - begin - Double (P); - Square (P); - end Math; - procedure Instance is new Math (Double => Half); - Number : Integer := 10; - - .. container:: column - - .. container:: column - - What is the value of Number after calling :ada:`Instance (Number)` - - A. 20 - B. 400 - C. :answer:`5` - D. 10 - -.. container:: animate - - A. Would be correct for :ada:`procedure Instance is new Math;` - - B. Would be correct for either :ada:`procedure Instance is new Math (Double, Square);` *or* :ada:`procedure Instance is new Math (Square => Square);` - - C. Correct - - * We call formal parameter :ada:`Double`, which has been assigned to actual subprogram :ada:`Half`, so :ada:`P`, which is 10, is halved. - - * Then we call formal parameter :ada:`Square`, which has no actual subprogram, so it defaults to :ada:`null`, so nothing happens to :ada:`P` - - D. Would be correct for either :ada:`procedure Instance is new Math (Double, Half);` *or* :ada:`procedure Instance is new Math (Square => Half);` - -.. - language_version 2005 - ----------------------- -Quiz Answer in Depth ----------------------- - - A. Wrong - result for :ada:`procedure Instance is new Math;` - B. Wrong - result for :ada:`procedure Instance is new Math (Double, Square);` - C. :ada:`Double` at line 10 is mapped to :ada:`Half` at line 3, and :ada:`Square` at line 11 wasn't specified so it defaults to :ada:`null` - D. Wrong - result for :ada:`procedure Instance is new Math (Square => Half);` - -.. container:: animate - - .. container:: latex_environment tiny - - :ada:`Math` is going to call two subprograms in order, :ada:`Double` and :ada:`Square`, but both of those come from the formal data. - - Whatever is used for :ada:`Double`, will be called by the :ada:`Math` instance. If nothing is passed in, the compiler tries to find a subprogram named :ada:`Double` and use that. If it doesn't, that's a compile error. - - Whatever is used for :ada:`Square`, will be called by the :ada:`Math` instance. If nothing is passed in, the compiler will treat this as a null call. - - In our case, :ada:`Half` is passed in for the first subprogram, but nothing is passed in for the second, so that call will just be null. - - So the final answer should be 5 (hence letter C). - -==================== -Generic Completion -==================== - ------------------------------- -Implications at Compile-Time ------------------------------- - -* The body needs to be visible when compiling the user code -* Therefore, when distributing a component with generics to be instantiated, the code of the generic must come along - ------------------------------ -Generic and Freezing Points ------------------------------ - -* A generic type **freezes** the type and needs the **full view** -* May force separation between its declaration (in spec) and instantiations (in private or body) - -.. code:: Ada - - generic - type X is private; - package Base is - V : access X; - end Base; - - package P is - type X is private; - -- illegal - package B is new Base (X); - private - type X is null record; - end P; - -------------------------------- -Generic Incomplete Parameters -------------------------------- - -* A generic type can be incomplete -* Allows generic instantiations before full type definition -* Restricts the possible usages (only :ada:`access`) - -.. code:: Ada - - generic - type X; -- incomplete - package Base is - V : access X; - end Base; - - package P is - type X is private; - -- legal - package B is new Base (X); - private - type X is null record; - end P; - ------- -Quiz ------- - -.. include:: quiz/genericity_private_type/quiz.rst - -======== -Lab -======== - -.. include:: labs/160_genericity.lab.rst - -========= -Summary -========= - -------------------------------------- -Generic Routines Vs Common Routines -------------------------------------- - -.. code:: Ada - - package Helper is - type Float_T is digits 6; - generic - type Type_T is digits <>; - Min : Type_T; - Max : Type_T; - function In_Range_Generic (X : Type_T) return Boolean; - function In_Range_Common (X : Float_T; - Min : Float_T; - Max : Float_T) - return Boolean; - end Helper; - - procedure User is - type Speed_T is new Float_T range 0.0 .. 100.0; - B : Boolean; - function Valid_Speed is new In_Range_Generic - (Speed_T, Speed_T'First, Speed_T'Last); - begin - B := Valid_Speed (12.3); - B := In_Range_Common (12.3, Speed_T'First, Speed_T'Last); - -.. container:: speakernote - - Generics increase code size and readability - Common functions reduce size, but increase error possibilities - ---------- -Summary ---------- - -* Generics are useful for copying code that works the same just for different types - - - Sorting, containers, etc - -* Properly written generics only need to be tested once - - - But testing / debugging can be more difficult - -* Generic instantiations are best done at compile time - - - At the package level - - Can be run time expensive when done in subprogram scope +************ +Genericity +************ + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 160_genericity/01-introduction.rst +.. include:: 160_genericity/02-creating_generics.rst +.. include:: 160_genericity/03-generic_data_in_depth.rst +.. include:: 160_genericity/04-generic_formal_data_in_depth.rst +.. include:: 160_genericity/05-generic_completion.rst +.. include:: labs/160_genericity.lab.rst +.. include:: 160_genericity/99-summary.rst diff --git a/courses/fundamentals_of_ada/160_genericity/01-introduction.rst b/courses/fundamentals_of_ada/160_genericity/01-introduction.rst new file mode 100644 index 000000000..9f87959df --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/01-introduction.rst @@ -0,0 +1,99 @@ +============== +Introduction +============== + +------------------------- +The Notion of a Pattern +------------------------- + +* Sometimes algorithms can be abstracted from types and subprograms + + .. code:: Ada + + procedure Swap_Int (Left, Right : in out Integer) is + V : Integer := Left; + begin + Left := Right; + Right := V; + end Swap_Int; + + procedure Swap_Bool (Left, Right : in out Boolean) is + V : Boolean := Left; + begin + Left := Right; + Right := V; + end Swap_Bool; + +* It would be nice to extract these properties in some common pattern, and then just replace the parts that need to be replaced + + .. code:: Ada + + procedure Swap (Left, Right : in out (Integer | Boolean)) is + V : (Integer | Boolean) := Left; + begin + Left := Right; + Right := V; + end Swap; + +-------------------- +Solution: Generics +-------------------- + +* A :dfn:`generic unit` is a unit that does not exist +* It is a pattern based on properties +* The instantiation applies the pattern to certain parameters + +-------------------------------------- +Ada Generic Compared to C++ Template +-------------------------------------- + +.. container:: columns + + .. container:: column + + Ada Generic + + .. container:: latex_environment scriptsize + + .. code:: Ada + + -- specification + generic + type T is private; + procedure Swap (L, R : in out T); + + -- implementation + procedure Swap (L, R : in out T) is + Tmp : T := L; + begin + L := R; + R := Tmp; + end Swap; + + -- instance + procedure Swap_F is new Swap (Float); + + .. container:: column + + C++ Template + + .. container:: latex_environment scriptsize + + .. code:: C++ + + // prototype + template + void Swap (T & L, T & R); + + // implementation + template + void Swap (T & L, T & R) { + T Tmp = L; + L = R; + R = Tmp; + } + + // instance + int x, y; + Swap(x,y); + diff --git a/courses/fundamentals_of_ada/160_genericity/02-creating_generics.rst b/courses/fundamentals_of_ada/160_genericity/02-creating_generics.rst new file mode 100644 index 000000000..483ea69d0 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/02-creating_generics.rst @@ -0,0 +1,77 @@ +=================== +Creating Generics +=================== + +------------- +Declaration +------------- + +* Subprograms + + .. code:: Ada + + generic + type T is private; + procedure Swap (L, R : in out T); + +* Packages + + .. code:: Ada + + generic + type T is private; + package Stack is + procedure Push (Item : T); + end Stack; + +* Body is required + + - Will be specialized and compiled for **each instance** + +* Children of generic units have to be generic themselves + + .. code:: Ada + + generic + package Stack.Utilities is + procedure Print (S : Stack_T); + +------- +Usage +------- + +* Instantiated with the :ada:`new` keyword + +.. code:: Ada + + -- Standard library + function Convert is new Ada.Unchecked_Conversion + (Integer, Array_Of_4_Bytes); + -- Callbacks + procedure Parse_Tree is new Tree_Parser + (Visitor_Procedure); + -- Containers, generic data-structures + package Integer_Stack is new Stack (Integer); + +* Advanced usages for testing, proof, meta-programming + +------ +Quiz +------ + +Which one(s) of the following can be made generic? + +.. code:: Ada + + generic + type T is private; + + +A. :answermono:`package` +B. ``record`` +D. :answermono:`function` +C. ``array`` + +.. container:: animate + + Only packages, functions, and procedures, can be made generic. diff --git a/courses/fundamentals_of_ada/160_genericity/03-generic_data.rst b/courses/fundamentals_of_ada/160_genericity/03-generic_data.rst new file mode 100644 index 000000000..405b515c8 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/03-generic_data.rst @@ -0,0 +1,105 @@ +============== +Generic Data +============== + +------------- +Definitions +------------- + +* A formal generic parameter is a template +* Properties are either :dfn:`constraints` or :dfn:`capabilities` + + - Expressed from the **body** point of view + - Constraints: e.g. unconstrained, :ada:`limited` + - Capabilities: e.g. :ada:`tagged`, primitives + +.. code:: Ada + + generic + type Pv is private; -- allocation, copy, assignment, "=" + with procedure Sort (T : Pv); -- primitive of Pv + type Unc (<>) is private; -- allocation require a value + type Lim is limited private; -- no copy or comparison + type Disc is (<>); -- 'First, ordering + package Generic_Pkg is [...] + +* Actual parameter **may** require constraints, and **must** provide capabilities + +.. code:: Ada + + package Pkg is new Generic_Pkg ( + Pv => Integer, -- has capabilities of private + Sort => Sort -- procedure Sort (T : Integer) + Unc => String, -- uses "unconstrained" constraint + Lim => Float, -- does not use "limited" constraint + Disc => Boolean, -- has capability of discrete + ); + +------------------ +Syntax (partial) +------------------ + +.. code:: Ada + + type T1 is (<>); -- discrete + type T2 is range <>; -- Integer + type T3 is digits <>; -- float + type T4 is private; -- indefinite + type T5 (<>) is private; -- indefinite + type T6 is tagged private; + type T7 is array (Boolean) of Integer; + type T8 is access Integer; + type T9 is limited private; + +* Not limited to those choices + +.. code:: Ada + + type T is not null access all limited tagged private; + +------ +Quiz +------ + +Which of the following statement is true? + +A. Generic contracts define new types +B. Generic contracts can express any type constraint +C. :answer:`Generic contracts can express inheritance constraint` +D. Generic contracts can require a type to be numeric (:ada:`Real` or :ada:`Integer`) + +.. container:: animate + + A. No, the formal type and the actual type just have different views + B. Counter-example: representation clauses + +------ +Quiz +------ + +.. include:: ../quiz/generic_subp_syntax/quiz.rst + +------ +Quiz +------ + +.. code:: Ada + + generic + type T1 is (<>); + type T2 (<>) is private; + procedure G + (A : T1; + B : T2); + +Which is (are) legal instantiation(s)? + + A. ``procedure A is new G (String, Character);`` + B. :answermono:`procedure B is new G (Character, Integer);` + C. :answermono:`procedure C is new G (Integer, Boolean);` + D. :answermono:`procedure D is new G (Boolean, String);` + +.. container:: animate + + :ada:`T1` must be discrete - so an integer or an enumeration. :ada:`T2` can be any type + diff --git a/courses/fundamentals_of_ada/160_genericity/03-generic_data_in_depth.rst b/courses/fundamentals_of_ada/160_genericity/03-generic_data_in_depth.rst new file mode 100644 index 000000000..e0d7c76b6 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/03-generic_data_in_depth.rst @@ -0,0 +1,145 @@ +============== +Generic Data +============== + +-------------------------------- +Generic Types Parameters (1/3) +-------------------------------- + +* A generic parameter is a template +* It specifies the properties the generic body can rely on + + .. code:: Ada + + generic + type T1 is private; + type T2 (<>) is private; + type T3 is limited private; + package Parent is + +* The actual parameter must be no more restrictive then the :dfn:`generic contract` + +--------------------------------------- +Generic Types Parameters (2/3) +--------------------------------------- + +* Generic formal parameter tells generic what it is allowed to do with the type + +.. container:: latex_environment tiny + + .. list-table:: + + * - :ada:`type T1 is (<>);` + + - Discrete type; :ada:`'First`, :ada:`'Succ`, etc available + + * - :ada:`type T2 is range <>;` + + - Signed Integer type; appropriate mathematic operations allowed + + * - :ada:`type T3 is digits <>;` + + - Floating point type; appropriate mathematic operations allowed + + * - :ada:`type T4;` + + - Incomplete type; can only be used as target of :ada:`access` + + * - :ada:`type T5 is tagged private;` + + - :ada:`tagged` type; can extend the type + + * - :ada:`type T6 is private;` + + - No knowledge about the type other than assignment, comparison, object creation allowed + + * - :ada:`type T7 (<>) is private;` + + - :ada:`(<>)` indicates type can be unconstrained, so any object has to be initialized + +-------------------------------- +Generic Types Parameters (3/3) +-------------------------------- + +* The usage in the generic has to follow the contract + + * Generic Subprogram + + .. code:: Ada + + generic + type T (<>) is private; + procedure P (V : T); + procedure P (V : T) is + X1 : T := V; -- OK, can constrain by initialization + X2 : T; -- Compilation error, no constraint to this + begin + + * Instantiations + + .. code:: Ada + + type Limited_T is limited null record; + + -- unconstrained types are accepted + procedure P1 is new P (String); + + -- type is already constrained + -- (but generic will still always initialize objects) + procedure P2 is new P (Integer); + + -- Illegal: the type can't be limited because the generic + -- thinks it can make copies + procedure P3 is new P (Limited_T); + +------------------------------------ +Generic Parameters Can Be Combined +------------------------------------ + +* Consistency is checked at compile-time + +.. code:: Ada + + generic + type T (<>) is private; + type Acc is access all T; + type Index is (<>); + type Arr is array (Index range <>) of Acc; + function Element (Source : Arr; + Position : Index) + return T; + + type String_Ptr is access all String; + type String_Array is array (Integer range <>) + of String_Ptr; + + function String_Element is new Element + (T => String, + Acc => String_Ptr, + Index => Integer, + Arr => String_Array); + +------ +Quiz +------ + +.. code:: Ada + + generic + type T1 is (<>); + type T2 (<>) is private; + procedure G + (A : T1; + B : T2); + +Which is (are) legal instantiation(s)? + + A. ``procedure A is new G (String, Character);`` + B. :answermono:`procedure B is new G (Character, Integer);` + C. :answermono:`procedure C is new G (Integer, Boolean);` + D. :answermono:`procedure D is new G (Boolean, String);` + +.. container:: animate + + :ada:`T1` must be discrete - so an integer or an enumeration. :ada:`T2` can be any type + diff --git a/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data.rst b/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data.rst new file mode 100644 index 000000000..adcc50b35 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data.rst @@ -0,0 +1,68 @@ +===================== +Generic Formal Data +===================== + +-------------------------------------------- +Generic Constants and Variables Parameters +-------------------------------------------- + +.. container:: columns + + .. container:: column + + * Variables can be specified on the generic contract + * The mode specifies the way the variable can be used: + + - :ada:`in` |rightarrow| read only + - :ada:`in out` |rightarrow| read write + + * Generic variables can be defined after generic types + + .. container:: column + + .. code:: Ada + + generic + type T is private; + X1 : Integer; -- constant + X2 : in out T; -- variable + procedure P; + + V : Float; + + procedure P_I is new P + (T => Float, + X1 => 42, + X2 => V); + +------------------------------- +Generic Subprogram Parameters +------------------------------- + +* Subprograms can be defined in the generic contract +* Must be introduced by :ada:`with` to differ from the generic unit + + .. code:: Ada + + generic + with procedure Callback; + procedure P; + procedure P is + begin + Callback; + end P; + procedure Something is null; + procedure P_I is new P (Something); + +------ +Quiz +------ + +.. include:: ../quiz/genericity_type_and_variable/quiz.rst + +------ +Quiz +------ + +.. include:: ../quiz/genericity_limited_type/quiz.rst + diff --git a/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data_in_depth.rst b/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data_in_depth.rst new file mode 100644 index 000000000..1d65e1fb3 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data_in_depth.rst @@ -0,0 +1,184 @@ +===================== +Generic Formal Data +===================== + +-------------------------------------------- +Generic Constants/Variables As Parameters +-------------------------------------------- + +.. container:: columns + + .. container:: column + + * Variables can be specified on the generic contract + * The mode specifies the way the variable can be used: + + - :ada:`in` |rightarrow| read only + - :ada:`in out` |rightarrow| read write + + * Generic variables can be defined after generic types + + .. container:: column + + .. container:: latex_environment tiny + + * Generic package + + .. code:: Ada + + generic + type Element_T is private; + Array_Size : Positive; + High_Watermark : in out Element_T; + package Repository is + + * Generic instance + + .. code:: Ada + + V : Float; + Max : Float; + + procedure My_Repository is new Repository + (Element_T => Float, + Array_size => 10, + High_Watermark => Max); + +------------------------------- +Generic Subprogram Parameters +------------------------------- + +* Subprograms can be defined in the generic contract +* Must be introduced by :ada:`with` to differ from the generic unit + + .. code:: Ada + + generic + type T is private; + with function Less_Than (L, R : T) return Boolean; + function Max (L, R : T) return T; + + function Max (L, R : T) return T is + begin + if Less_Than (L, R) then + return R; + else + return L; + end if; + end Max; + + type Something_T is null record; + function Less_Than (L, R : Something_T) return Boolean; + procedure My_Max is new Max (Something_T, Less_Than); + +---------------------------------------- +Generic Subprogram Parameters Defaults +---------------------------------------- + +* :ada:`is <>` - matching subprogram is taken by default +* :ada:`is null` - null procedure is taken by default + + - Only available in Ada 2005 and later + + .. code:: Ada + + generic + type T is private; + with function Is_Valid (P : T) return Boolean is <>; + with procedure Error_Message (P : T) is null; + procedure Validate (P : T); + + function Is_Valid_Record (P : Record_T) return Boolean; + + procedure My_Validate is new Validate (Record_T, + Is_Valid_Record); + -- Is_Valid maps to Is_Valid_Record + -- Error_Message maps to a null procedure + +.. + language_version 2005 + +------ +Quiz +------ + +.. include:: ../quiz/genericity_type_and_variable/quiz.rst + +------ +Quiz +------ + +.. container:: columns + + .. container:: column + + + .. code:: Ada + :number-lines: 1 + + procedure Double (X : in out Integer); + procedure Square (X : in out Integer); + procedure Half (X : in out Integer); + generic + with procedure Double (X : in out Integer) is <>; + with procedure Square (X : in out Integer) is null; + procedure Math (P : in out Integer); + procedure Math (P : in out Integer) is + begin + Double (P); + Square (P); + end Math; + procedure Instance is new Math (Double => Half); + Number : Integer := 10; + + .. container:: column + + .. container:: column + + What is the value of Number after calling :ada:`Instance (Number)` + + A. 20 + B. 400 + C. :answer:`5` + D. 10 + +.. container:: animate + + A. Would be correct for :ada:`procedure Instance is new Math;` + + B. Would be correct for either :ada:`procedure Instance is new Math (Double, Square);` *or* :ada:`procedure Instance is new Math (Square => Square);` + + C. Correct + + * We call formal parameter :ada:`Double`, which has been assigned to actual subprogram :ada:`Half`, so :ada:`P`, which is 10, is halved. + + * Then we call formal parameter :ada:`Square`, which has no actual subprogram, so it defaults to :ada:`null`, so nothing happens to :ada:`P` + + D. Would be correct for either :ada:`procedure Instance is new Math (Double, Half);` *or* :ada:`procedure Instance is new Math (Square => Half);` + +.. + language_version 2005 + +---------------------- +Quiz Answer in Depth +---------------------- + + A. Wrong - result for :ada:`procedure Instance is new Math;` + B. Wrong - result for :ada:`procedure Instance is new Math (Double, Square);` + C. :ada:`Double` at line 10 is mapped to :ada:`Half` at line 3, and :ada:`Square` at line 11 wasn't specified so it defaults to :ada:`null` + D. Wrong - result for :ada:`procedure Instance is new Math (Square => Half);` + +.. container:: animate + + .. container:: latex_environment tiny + + :ada:`Math` is going to call two subprograms in order, :ada:`Double` and :ada:`Square`, but both of those come from the formal data. + + Whatever is used for :ada:`Double`, will be called by the :ada:`Math` instance. If nothing is passed in, the compiler tries to find a subprogram named :ada:`Double` and use that. If it doesn't, that's a compile error. + + Whatever is used for :ada:`Square`, will be called by the :ada:`Math` instance. If nothing is passed in, the compiler will treat this as a null call. + + In our case, :ada:`Half` is passed in for the first subprogram, but nothing is passed in for the second, so that call will just be null. + + So the final answer should be 5 (hence letter C). + diff --git a/courses/fundamentals_of_ada/160_genericity/05-generic_completion.rst b/courses/fundamentals_of_ada/160_genericity/05-generic_completion.rst new file mode 100644 index 000000000..dc7a55bac --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/05-generic_completion.rst @@ -0,0 +1,63 @@ +==================== +Generic Completion +==================== + +------------------------------ +Implications at Compile-Time +------------------------------ + +* The body needs to be visible when compiling the user code +* Therefore, when distributing a component with generics to be instantiated, the code of the generic must come along + +----------------------------- +Generic and Freezing Points +----------------------------- + +* A generic type **freezes** the type and needs the **full view** +* May force separation between its declaration (in spec) and instantiations (in private or body) + +.. code:: Ada + + generic + type X is private; + package Base is + V : access X; + end Base; + + package P is + type X is private; + -- illegal + package B is new Base (X); + private + type X is null record; + end P; + +------------------------------- +Generic Incomplete Parameters +------------------------------- + +* A generic type can be incomplete +* Allows generic instantiations before full type definition +* Restricts the possible usages (only :ada:`access`) + +.. code:: Ada + + generic + type X; -- incomplete + package Base is + V : access X; + end Base; + + package P is + type X is private; + -- legal + package B is new Base (X); + private + type X is null record; + end P; + +------ +Quiz +------ + +.. include:: ../quiz/genericity_private_type/quiz.rst diff --git a/courses/fundamentals_of_ada/160_genericity/99-summary.rst b/courses/fundamentals_of_ada/160_genericity/99-summary.rst new file mode 100644 index 000000000..8d193c31a --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/99-summary.rst @@ -0,0 +1,53 @@ +========= +Summary +========= + +------------------------------------- +Generic Routines Vs Common Routines +------------------------------------- + +.. code:: Ada + + package Helper is + type Float_T is digits 6; + generic + type Type_T is digits <>; + Min : Type_T; + Max : Type_T; + function In_Range_Generic (X : Type_T) return Boolean; + function In_Range_Common (X : Float_T; + Min : Float_T; + Max : Float_T) + return Boolean; + end Helper; + + procedure User is + type Speed_T is new Float_T range 0.0 .. 100.0; + B : Boolean; + function Valid_Speed is new In_Range_Generic + (Speed_T, Speed_T'First, Speed_T'Last); + begin + B := Valid_Speed (12.3); + B := In_Range_Common (12.3, Speed_T'First, Speed_T'Last); + +.. container:: speakernote + + Generics increase code size and readability + Common functions reduce size, but increase error possibilities + +--------- +Summary +--------- + +* Generics are useful for copying code that works the same just for different types + + - Sorting, containers, etc + +* Properly written generics only need to be tested once + + - But testing / debugging can be more difficult + +* Generic instantiations are best done at compile time + + - At the package level + - Can be run time expensive when done in subprogram scope diff --git a/courses/fundamentals_of_ada/intro_160_genericity.rst b/courses/fundamentals_of_ada/intro_160_genericity.rst deleted file mode 100644 index 7a12f82b9..000000000 --- a/courses/fundamentals_of_ada/intro_160_genericity.rst +++ /dev/null @@ -1,382 +0,0 @@ -************ -Genericity -************ - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - -------------------------- -The Notion of a Pattern -------------------------- - -* Sometimes algorithms can be abstracted from types and subprograms - - .. code:: Ada - - procedure Swap_Int (Left, Right : in out Integer) is - V : Integer; - begin - V := Left; - Left := Right; - Right := V; - end Swap_Int; - - procedure Swap_Bool (Left, Right : in out Boolean) is - V : Boolean; - begin - V := Left; - Left := Right; - Right := V; - end Swap_Bool; - -* It would be nice to extract these properties in some common pattern, and then just replace the parts that need to be replaced - - .. code:: Ada - - -- T := Integer | Boolean - procedure Swap (Left, Right : in out T) is - V : T; - begin - V := Left; - Left := Right; - Right := V; - end Swap; - --------------------- -Solution: Generics --------------------- - -* A :dfn:`generic unit` is a code pattern which can be reused - - - Does not get compiled as-is - -* The instantiation applies the pattern to certain parameters - - - Based on properties - - Use a :dfn:`generic contract` - - Parameters can be constant, variable, subprogram, type, package - -======== -Syntax -======== - -------- -Usage -------- - -* Instantiated with the :ada:`new` keyword - -.. code:: Ada - - -- Standard library - function Convert is new Ada.Unchecked_Conversion - (Integer, Array_Of_4_Bytes); - -- Callbacks - procedure Parse_Tree is new Tree_Parser - (Visitor_Procedure); - -- Containers, generic data-structures - package Integer_Stack is new Stack (Integer); - -* Advanced usages for testing, proof, meta-programming - -------------- -Declaration -------------- - -* Subprograms - - .. code:: Ada - - generic - type T is private; - procedure Swap (L, R : in out T); - -* Packages - - .. code:: Ada - - generic - type T is private; - package Stack is - procedure Push (Item : T); - end Stack; - -* Body is required - - - Will be specialized and compiled for **each instance** - ------- -Quiz ------- - -Which of the following statement is true? - -A. :answer:`Generics allow for code reuse` -B. :answer:`Generics can take packages as parameters` -C. Genericity is specific to Ada -D. :answer:`Genericity is available in all versions of Ada and/or SPARK` - ------- -Quiz ------- - -Which one(s) of the following can be made generic? - -.. code:: Ada - - generic - type T is private; - - -A. :answermono:`package` -B. ``record`` -D. :answermono:`function` -C. ``array`` - -.. container:: animate - - Only packages, functions, and procedures, can be made generic. - ------- -Quiz ------- - -Which of the following statement is true? - -A. Generic instances must be nested inside a non-generic package -B. Generic instances must be instantiated at compile-time -C. :answer:`Generics instances can create new tagged types` -D. :answer:`Generics instances can create new tasks` - -.. container:: animate - - Generic instances can be instantiated at any point, at a cost, and - can do anything a package or subprogram can do, which make them - versatile **but** potentially complex to use. - -=================== -Generic Contracts -=================== - -------------- -Definitions -------------- - -* A formal generic parameter is a template -* Properties are either :dfn:`constraints` or :dfn:`capabilities` - - - Expressed from the **body** point of view - - Constraints: e.g. unconstrained, :ada:`limited` - - Capabilities: e.g. :ada:`tagged`, primitives - -.. code:: Ada - - generic - type Pv is private; -- allocation, copy, assignment, "=" - with procedure Sort (T : Pv); -- primitive of Pv - type Unc (<>) is private; -- allocation require a value - type Lim is limited private; -- no copy or comparison - type Disc is (<>); -- 'First, ordering - package Generic_Pkg is [...] - -* Actual parameter **may** require constraints, and **must** provide capabilities - -.. code:: Ada - - package Pkg is new Generic_Pkg ( - Pv => Integer, -- has capabilities of private - Sort => Sort -- procedure Sort (T : Integer) - Unc => String, -- uses "unconstrained" constraint - Lim => Float, -- does not use "limited" constraint - Disc => Boolean, -- has capability of discrete - ); - ------------------- -Syntax (partial) ------------------- - -.. code:: Ada - - type T1 is (<>); -- discrete - type T2 is range <>; -- Integer - type T3 is digits <>; -- float - type T4 is private; -- indefinite - type T5 (<>) is private; -- indefinite - type T6 is tagged private; - type T7 is array (Boolean) of Integer; - type T8 is access Integer; - type T9 is limited private; - -* Not limited to those choices - -.. code:: Ada - - type T is not null access all limited tagged private; - ------- -Quiz ------- - -Which of the following statement is true? - -A. Generic contracts define new types -B. Generic contracts can express any type constraint -C. :answer:`Generic contracts can express inheritance constraint` -D. Generic contracts can require a type to be numeric (:ada:`Real` or :ada:`Integer`) - -.. container:: animate - - A. No, the formal type and the actual type just have different views - B. Counter-example: representation clauses - ------- -Quiz ------- - -.. include:: quiz/generic_subp_syntax/quiz.rst - ------- -Quiz ------- - -.. code:: Ada - - generic - type T1 is (<>); - type T2 (<>) is private; - procedure G - (A : T1; - B : T2); - -Which is (are) legal instantiation(s)? - - A. ``procedure A is new G (String, Character);`` - B. :answermono:`procedure B is new G (Character, Integer);` - C. :answermono:`procedure C is new G (Integer, Boolean);` - D. :answermono:`procedure D is new G (Boolean, String);` - -.. container:: animate - - :ada:`T1` must be discrete - so an integer or an enumeration. :ada:`T2` can be any type - -===================== -Generic Formal Data -===================== - --------------------------------------------- -Generic Constants and Variables Parameters --------------------------------------------- - -.. container:: columns - - .. container:: column - - * Variables can be specified on the generic contract - * The mode specifies the way the variable can be used: - - - :ada:`in` |rightarrow| read only - - :ada:`in out` |rightarrow| read write - - * Generic variables can be defined after generic types - - .. container:: column - - .. code:: Ada - - generic - type T is private; - X1 : Integer; -- constant - X2 : in out T; -- variable - procedure P; - - V : Float; - - procedure P_I is new P - (T => Float, - X1 => 42, - X2 => V); - -------------------------------- -Generic Subprogram Parameters -------------------------------- - -* Subprograms can be defined in the generic contract -* Must be introduced by :ada:`with` to differ from the generic unit - - .. code:: Ada - - generic - with procedure Callback; - procedure P; - procedure P is - begin - Callback; - end P; - procedure Something is null; - procedure P_I is new P (Something); - ------- -Quiz ------- - -.. include:: quiz/genericity_type_and_variable/quiz.rst - ------- -Quiz ------- - -.. include:: quiz/genericity_limited_type/quiz.rst - -========= -Summary -========= - ---------- -Summary ---------- - -* Generics are useful for **reusing code** - - - Sorting, containers, etc - -* Generic contracts syntax is different from Ada declaration - - - But has some resemblance to it - - e.g. discretes' :ada:`type Enum is (A, B, C)` vs generics' :ada:`type T is (<>)` - -* Instantiation "generates" code - - - Costly - - Beware of local generic instances!