From 88d2a38c80cc17ef6f6d55431b86f8f5b2b093eb Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:09:38 +0200 Subject: [PATCH 01/14] Editorial change: fixing anchor --- .../advanced-ada/parts/resource_management/access_types.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/resource_management/access_types.rst b/content/courses/advanced-ada/parts/resource_management/access_types.rst index 839e5e0e7..c07c1b32f 100644 --- a/content/courses/advanced-ada/parts/resource_management/access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/access_types.rst @@ -3438,8 +3438,6 @@ If :ada:`X (Index)` occurs inside :ada:`Process_Array`, there is no need to check that :ada:`Index` is in range, because the check is pushed to the caller. -.. _Adv_Ada_Access_To_Subprograms: - .. _Adv_Ada_Design_Strategies_Access_Types: Design strategies for access types @@ -3467,6 +3465,8 @@ Design strategies for access types Finalize can call Free. +.. _Adv_Ada_Access_To_Subprograms: + Access to subprograms --------------------- From 1dbf32d846c319550d00c9e745798988f99c8343 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:10:24 +0200 Subject: [PATCH 02/14] Editorial change: splitting code example into two blocks --- .../parts/resource_management/access_types.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/resource_management/access_types.rst b/content/courses/advanced-ada/parts/resource_management/access_types.rst index c07c1b32f..8ffe16f52 100644 --- a/content/courses/advanced-ada/parts/resource_management/access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/access_types.rst @@ -3561,9 +3561,10 @@ the :ada:`P` procedure by simply passing :ada:`I` as a parameter. In this case, :ada:`P` is automatically dereferenced. We may, however, explicitly dereference :ada:`P` by writing :ada:`P.all (I)`. -Next, we can get access to a subprogram by using the :ada:`Access` attribute: +Before we use this package, let's implement a simple procedure that we'll use +later on: -.. code:: ada run_button main=show_access_to_subprograms.adb project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types procedure Add_Ten (I : in out Integer); @@ -3572,6 +3573,11 @@ Next, we can get access to a subprogram by using the :ada:`Access` attribute: I := I + 10; end Add_Ten; +Now, we can get access to a subprogram by using the :ada:`Access` attribute and +pass it as an actual parameter: + +.. code:: ada run_button main=show_access_to_subprograms.adb project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + with Access_To_Subprogram_Params; use Access_To_Subprogram_Params; From cc5f5fc20d68be7e809e80220175cbc58957ad63 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:10:38 +0200 Subject: [PATCH 03/14] Editorial change: adding anchor --- .../advanced-ada/parts/resource_management/access_types.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/courses/advanced-ada/parts/resource_management/access_types.rst b/content/courses/advanced-ada/parts/resource_management/access_types.rst index 8ffe16f52..f1bf3046e 100644 --- a/content/courses/advanced-ada/parts/resource_management/access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/access_types.rst @@ -3573,6 +3573,8 @@ later on: I := I + 10; end Add_Ten; +.. _Adv_Ada_Access_To_Subprogram_Params_Example: + Now, we can get access to a subprogram by using the :ada:`Access` attribute and pass it as an actual parameter: From c47ccfdf39111bdcfc6e1611115b50f3dbd5f1d1 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:11:26 +0200 Subject: [PATCH 04/14] Adding subsection on objects of access-to-subprogram types --- .../resource_management/access_types.rst | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/content/courses/advanced-ada/parts/resource_management/access_types.rst b/content/courses/advanced-ada/parts/resource_management/access_types.rst index f1bf3046e..8a917a09d 100644 --- a/content/courses/advanced-ada/parts/resource_management/access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/access_types.rst @@ -3601,6 +3601,78 @@ Here, we get access to the :ada:`Add_Ten` procedure and pass it to the - :arm22:`3.10 Access Types <3-10>` +Objects of access-to-subprogram type +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the previous example, the :ada:`Proc` procedure had a parameter of +access-to-subprogram type. In addition to parameters, we can of course declare +*objects* of access-to-subprogram types as well. For example, we can extend +our previous test application and declare an object :ada:`P` of +access-to-subprogram type. Before we do so, however, let's implement another +small procedure that we'll use later on: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + procedure Add_Twenty (I : in out Integer); + + procedure Add_Twenty (I : in out Integer) is + begin + I := I + 20; + end Add_Twenty; + +In addition to :ada:`Add_Ten`, we've implemented the :ada:`Add_Twenty` +procedure, which we use in our extended test application: + +.. code:: ada run_button main=show_access_to_subprograms.adb project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + with Access_To_Subprogram_Types; + use Access_To_Subprogram_Types; + + with Access_To_Subprogram_Params; + use Access_To_Subprogram_Params; + + with Add_Ten; + with Add_Twenty; + + procedure Show_Access_To_Subprograms is + P : Access_To_Procedure; + Some_Int : Integer := 0; + begin + P := Add_Ten'Access; + -- ^ Getting access to Add_Ten + -- procedure and assigning it + -- to P + + Proc (P); + -- ^ Passing access-to-subprogram as an + -- actual parameter + + P (Some_Int); + -- ^ Using access-to-subprogram object in a + -- subprogram call + + P := Add_Twenty'Access; + -- ^ Getting access to Add_Twenty + -- procedure and assigning it + -- to P + + Proc (P); + P (Some_Int); + end Show_Access_To_Subprograms; + +In the :ada:`Show_Access_To_Subprograms` procedure, +we see the declaration of our access-to-subprogram object :ada:`P` (of +:ada:`Access_To_Procedure` type). We get access to the :ada:`Add_Ten` procedure +and assign it to :ada:`P`, and we then do the same for the :ada:`Add_Twenty` +procedure. + +We can use an access-to-subprogram object either as the actual parameter of a +subprogram call, or in a subprogram call. In the code example, we're passing +:ada:`P` as the actual parameter of the :ada:`Proc` procedure +(in the :ada:`Proc (P)` calls), and we're calling the subprogram assigned to +:ada:`P` (in the :ada:`P (Some_Int)` calls). + + Selecting subprograms ~~~~~~~~~~~~~~~~~~~~~ From 9a26fa38d25d34e83140c4f210ba1e5d92f5eaf2 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:12:06 +0200 Subject: [PATCH 05/14] Adding subsection on components of access-to-subprogram types --- .../resource_management/access_types.rst | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/content/courses/advanced-ada/parts/resource_management/access_types.rst b/content/courses/advanced-ada/parts/resource_management/access_types.rst index 8a917a09d..c516b3d93 100644 --- a/content/courses/advanced-ada/parts/resource_management/access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/access_types.rst @@ -3673,6 +3673,117 @@ subprogram call, or in a subprogram call. In the code example, we're passing :ada:`P` (in the :ada:`P (Some_Int)` calls). +Components of access-to-subprogram type +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In addition to declaring subprogram parameters and objects of +access-to-subprogram types, we can declare components of these types. For +example: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + package Access_To_Subprogram_Types is + + type Access_To_Procedure is + access procedure (I : in out Integer); + + type Access_To_Function is + access function (I : Integer) return Integer; + + type Access_To_Procedure_Array is + array (Positive range <>) of + Access_To_Procedure; + + type Access_To_Function_Array is + array (Positive range <>) of + Access_To_Function; + + type Rec_Access_To_Procedure is record + AP : Access_To_Procedure; + end record; + + type Rec_Access_To_Function is record + AF : Access_To_Function; + end record; + + end Access_To_Subprogram_Types; + +Here, the access-to-procedure type :ada:`Access_To_Procedure` is used as a +component of the array type :ada:`Access_To_Procedure_Array` and the record +type :ada:`Rec_Access_To_Procedure`. Similarly, the access-to-function type +:ada:`Access_To_Function` type is used as a component of the array type +:ada:`Access_To_Function_Array` and the record type +:ada:`Rec_Access_To_Function`. + +Let's see two test applications using these types. First, let's use the +:ada:`Access_To_Procedure_Array` array type in a test application: + +.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + with Ada.Text_IO; use Ada.Text_IO; + + with Access_To_Subprogram_Types; + use Access_To_Subprogram_Types; + + with Add_Ten; + with Add_Twenty; + + procedure Show_Access_To_Subprograms is + PA : constant + Access_To_Procedure_Array (1 .. 2) := + (Add_Ten'Access, + Add_Twenty'Access); + + Some_Int : Integer := 0; + begin + Put_Line ("Some_Int: " & Some_Int'Image); + + for I in PA'Range loop + PA (I) (Some_Int); + Put_Line ("Some_Int: " & Some_Int'Image); + end loop; + end Show_Access_To_Subprograms; + +Here, we declare the :ada:`PA` array and use the access to the :ada:`Add_Ten` +and :ada:`Add_Twenty` procedures as its components. We can call any of these +procedures by simply specifying the index of the component, e.g. +:ada:`PA (2)`. Once we specify the procedure we want to use, we simply pass +the parameters, e.g.: :ada:`PA (2) (Some_Int)`. + +Now, let's use the :ada:`Rec_Access_To_Procedure` record type in a test +application: + +.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + with Ada.Text_IO; use Ada.Text_IO; + + with Access_To_Subprogram_Types; + use Access_To_Subprogram_Types; + + with Add_Ten; + with Add_Twenty; + + procedure Show_Access_To_Subprograms is + RA : Rec_Access_To_Procedure; + Some_Int : Integer := 0; + begin + Put_Line ("Some_Int: " & Some_Int'Image); + + RA := (AP => Add_Ten'Access); + RA.AP (Some_Int); + Put_Line ("Some_Int: " & Some_Int'Image); + + RA := (AP => Add_Twenty'Access); + RA.AP (Some_Int); + Put_Line ("Some_Int: " & Some_Int'Image); + end Show_Access_To_Subprograms; + +Here, we declare two record aggregates where we specify the :ada:`AP` +component, e.g.: :ada:`(AP => Add_Ten'Access)`, which indicates the +access-to-subprogram we want to use. We can call the subprogram by simply +accessing the :ada:`AP` component, i.e.: :ada:`RA.AP`. + + Selecting subprograms ~~~~~~~~~~~~~~~~~~~~~ From 44f6624701d2213d39dfd6af759e4395d2ad18a3 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:12:47 +0200 Subject: [PATCH 06/14] Adding subsection on access-to-subprograms as discriminant types --- .../resource_management/access_types.rst | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/content/courses/advanced-ada/parts/resource_management/access_types.rst b/content/courses/advanced-ada/parts/resource_management/access_types.rst index c516b3d93..f5bcd3f14 100644 --- a/content/courses/advanced-ada/parts/resource_management/access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/access_types.rst @@ -3784,6 +3784,136 @@ access-to-subprogram we want to use. We can call the subprogram by simply accessing the :ada:`AP` component, i.e.: :ada:`RA.AP`. +Access-to-subprogram as discriminant types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As you might expect, we can use access-to-subprogram types when declaring +discriminants. In fact, when we were talking about +:ref:`discriminants as access values ` +earlier on, we used access-to-object types in our code examples, but we could +have used access-to-subprogram types as well. For example: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + package Custom_Processing is + + -- Declaring an access type: + type Integer_Processing is + access procedure (I : in out Integer); + + -- Declaring a discriminant with this + -- access type: + type Rec (IP : Integer_Processing) is + private; + + procedure Init (R : in out Rec; + Value : Integer); + + procedure Process (R : in out Rec); + + procedure Show (R : Rec); + + private + + type Rec (IP : Integer_Processing) is + record + I : Integer := 0; + end record; + + end Custom_Processing; + + with Ada.Text_IO; use Ada.Text_IO; + + package body Custom_Processing is + + procedure Init (R : in out Rec; + Value : Integer) is + begin + R.I := Value; + end Init; + + procedure Process (R : in out Rec) is + begin + R.IP (R.I); + -- ^^^^^^ + -- Calling procedure that we specified as + -- the record's discriminant + end Process; + + procedure Show (R : Rec) is + begin + Put_Line ("R.I = " + & Integer'Image (R.I)); + end Show; + + end Custom_Processing; + +In this example, we declare the access-to-subprogram type +:ada:`Integer_Processing`, which we use as the :ada:`IP` discriminant of the +:ada:`Rec` type. In the :ada:`Process` procedure, we call the :ada:`IP` +procedure that we specified as the record's discriminant (:ada:`R.IP (R.I)`). + +Before we look at a test application for this package, let's implement +another small procedure: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + procedure Mult_Two (I : in out Integer); + + procedure Mult_Two (I : in out Integer) is + begin + I := I * 2; + end Mult_Two; + +Now, let's look at the test application: + +.. code:: ada run_button main=show_access_to_subprogram_discriminants.adb project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + with Ada.Text_IO; use Ada.Text_IO; + + with Custom_Processing; use Custom_Processing; + + with Add_Ten; + with Mult_Two; + + procedure Show_Access_To_Subprogram_Discriminants + is + + R_Add_Ten : Rec (IP => Add_Ten'Access); + -- ^^^^^^^^^^^^^^^^^^^^ + -- Using access-to-subprogram as a + -- discriminant + + R_Mult_Two : Rec (IP => Mult_Two'Access); + -- ^^^^^^^^^^^^^^^^^^^^^ + -- Using access-to-subprogram as a + -- discriminant + + begin + Init (R_Add_Ten, 1); + Init (R_Mult_Two, 2); + + Put_Line ("---- R_Add_Ten ----"); + Show (R_Add_Ten); + + Put_Line ("Calling Process procedure..."); + Process (R_Add_Ten); + Show (R_Add_Ten); + + Put_Line ("---- R_Mult_Two ----"); + Show (R_Mult_Two); + + Put_Line ("Calling Process procedure..."); + Process (R_Mult_Two); + Show (R_Mult_Two); + end Show_Access_To_Subprogram_Discriminants; + +In this procedure, we declare the :ada:`R_Add_Ten` and :ada:`R_Mult_Two` of +:ada:`Rec` type and specify the access to :ada:`Add_Ten` and :ada:`Mult_Two`, +respectively, as the :ada:`IP` discriminant. The procedure we specified here +is then called inside a call to the :ada:`Process` procedure. + + Selecting subprograms ~~~~~~~~~~~~~~~~~~~~~ From 599cbdb6ce45f97722b3c3553768cf1a598f71cb Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:14:18 +0200 Subject: [PATCH 07/14] Adding subsection on access-to-subprograms as formal parameters --- .../resource_management/access_types.rst | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/content/courses/advanced-ada/parts/resource_management/access_types.rst b/content/courses/advanced-ada/parts/resource_management/access_types.rst index f5bcd3f14..4a2b36c55 100644 --- a/content/courses/advanced-ada/parts/resource_management/access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/access_types.rst @@ -3914,6 +3914,130 @@ respectively, as the :ada:`IP` discriminant. The procedure we specified here is then called inside a call to the :ada:`Process` procedure. +Access-to-subprograms as formal parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We can use access-to-subprograms types when declaring formal parameters. For +example, let's revisit the :ada:`Custom_Processing` package from the previous +section and convert it into a generic package. + +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + generic + type T is private; + + -- + -- Declaring formal access-to-subprogram + -- type: + -- + type T_Processing is + access procedure (Element : in out T); + + -- + -- Declaring formal access-to-subprogram + -- parameter: + -- + Proc : T_Processing; + + with function Image_T (Element : T) + return String; + package Gen_Custom_Processing is + + type Rec is private; + + procedure Init (R : in out Rec; + Value : T); + + procedure Process (R : in out Rec); + + procedure Show (R : Rec); + + private + + type Rec is record + Comp : T; + end record; + + end Gen_Custom_Processing; + + with Ada.Text_IO; use Ada.Text_IO; + + package body Gen_Custom_Processing is + + procedure Init (R : in out Rec; + Value : T) is + begin + R.Comp := Value; + end Init; + + procedure Process (R : in out Rec) is + begin + Proc (R.Comp); + end Process; + + procedure Show (R : Rec) is + begin + Put_Line ("R.Comp = " + & Image_T (R.Comp)); + end Show; + + end Gen_Custom_Processing; + +In this version of the procedure, instead of declaring :ada:`Proc` as a +discriminant of the :ada:`Rec` record, we're declaring it as a formal parameter +of the :ada:`Gen_Custom_Processing` package. Also, we're declaring an +access-to-subprogram type (:ada:`T_Processing`) as a formal parameter. (Note +that, in contrast to these two parameters that we've just mentioned, +:ada:`Image_T` is not a formal access-to-subprogram parameter: it's actually +just a formal subprogram.) + +We then instantiate the :ada:`Gen_Custom_Processing` package in our test +application: + +.. code:: ada run_button main=show_access_to_subprogram_as_formal_parameter.adb project=Courses.Advanced_Ada.Resource_Management.Access_Types.Access_To_Subprograms.Access_To_Subprogram_Types + + with Gen_Custom_Processing; + + with Add_Ten; + + with Ada.Text_IO; use Ada.Text_IO; + + procedure + Show_Access_To_Subprogram_As_Formal_Parameter + is + type Integer_Processing is + access procedure (I : in out Integer); + + package Custom_Processing is new + Gen_Custom_Processing + (T => Integer, + T_Processing => Integer_Processing, + -- ^^^^^^^^^^^^^^^^^^ + -- access-to-subprogram type + Proc => Add_Ten'Access, + -- ^^^^^^^^^^^^^^^^^^ + -- access-to-subprogram + Image_T => Integer'Image); + use Custom_Processing; + + R_Add_Ten : Rec; + + begin + Init (R_Add_Ten, 1); + + Put_Line ("---- R_Add_Ten ----"); + Show (R_Add_Ten); + + Put_Line ("Calling Process procedure..."); + Process (R_Add_Ten); + Show (R_Add_Ten); + end Show_Access_To_Subprogram_As_Formal_Parameter; + +Here, we instantiate the :ada:`Gen_Custom_Processing` package as +:ada:`Custom_Processing` and specify the access-to-subprogram type and the +access-to-subprogram. + + Selecting subprograms ~~~~~~~~~~~~~~~~~~~~~ From 12ecefe376a4fde0e3d5f33ffeef7d367e7ba279 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:22:52 +0200 Subject: [PATCH 08/14] Minor editorial changes in code example - Renaming procedures; - Splitting code blocks. - Adding procedure: Add_Twenty --- .../anonymous_access_types.rst | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst index 982d2f987..bfcba23bd 100644 --- a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst @@ -1549,16 +1549,17 @@ Anonymous Access-To-Subprograms We can declare subprogram parameters using anonymous types: -.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Access_To_Subprograms.Access_To_Subprogram_Params - package Access_To_Subprogram_Params is +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Anonymous_Access_To_Subprograms.Anonymous_Access_To_Subprogram_Example + + package Anonymous_Access_To_Subprogram is procedure Proc (P : access procedure (I : in out Integer)); - end Access_To_Subprogram_Params; + end Anonymous_Access_To_Subprogram; - package body Access_To_Subprogram_Params is + package body Anonymous_Access_To_Subprogram is procedure Proc (P : access procedure (I : in out Integer)) @@ -1569,7 +1570,9 @@ We can declare subprogram parameters using anonymous types: P.all (I); end Proc; - end Access_To_Subprogram_Params; + end Anonymous_Access_To_Subprogram; + +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Anonymous_Access_To_Subprograms.Anonymous_Access_To_Subprogram_Example procedure Add_Ten (I : in out Integer); @@ -1578,18 +1581,27 @@ We can declare subprogram parameters using anonymous types: I := I + 10; end Add_Ten; - with Access_To_Subprogram_Params; - use Access_To_Subprogram_Params; + procedure Add_Twenty (I : in out Integer); + + procedure Add_Twenty (I : in out Integer) is + begin + I := I + 20; + end Add_Twenty; + +.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Anonymous_Access_To_Subprograms.Anonymous_Access_To_Subprogram_Example + + with Anonymous_Access_To_Subprogram; + use Anonymous_Access_To_Subprogram; with Add_Ten; - procedure Show_Access_To_Subprograms is + procedure Show_Anonymous_Access_To_Subprograms is begin Proc (Add_Ten'Access); -- ^ Getting access to Add_Ten -- procedure and passing it -- to Proc - end Show_Access_To_Subprograms; + end Show_Anonymous_Access_To_Subprograms; .. admonition:: In the Ada Reference Manual From 8f206e92f653614639867115ed8839443b6437b5 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:23:52 +0200 Subject: [PATCH 09/14] Editorial change: using dereferenced version --- .../parts/resource_management/anonymous_access_types.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst index bfcba23bd..6a128d7ee 100644 --- a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst @@ -1566,8 +1566,7 @@ We can declare subprogram parameters using anonymous types: is I : Integer := 0; begin - -- P (I); - P.all (I); + P (I); end Proc; end Anonymous_Access_To_Subprogram; From f687de77231964b7ce07df1ec85c3ad65c8e4080 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:24:47 +0200 Subject: [PATCH 10/14] Completing introductory subsection on anonymous access-to-subprogram types --- .../anonymous_access_types.rst | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst index 6a128d7ee..ffb51886a 100644 --- a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst @@ -1547,8 +1547,13 @@ access objects doesn't impose additional hurdles. Anonymous Access-To-Subprograms ------------------------------- -We can declare subprogram parameters using anonymous types: +In the previous chapter, we talked about +:ref:`named access-to-subprogram types `. Now, +we'll see that the anonymous version of those types isn't much different from +the named version. +Let's start our discussion by declaring a subprogram parameter using an +anonymous access-to-procedure type: .. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Anonymous_Access_To_Subprograms.Anonymous_Access_To_Subprogram_Example @@ -1571,6 +1576,16 @@ We can declare subprogram parameters using anonymous types: end Anonymous_Access_To_Subprogram; +In this example, we use the anonymous +:ada:`access procedure (I : in out Integer)` type as a parameter of the +:ada:`Proc` procedure. Note that we need an identifier in the declaration: +we cannot leave :ada:`I` out and write +:ada:`access procedure (in out Integer)`. + +Before we look at a test application that makes use of the +:ada:`Anonymous_Access_To_Subprogram` package, let's implement two simple +procedures that we'll use later on: + .. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Anonymous_Access_To_Subprograms.Anonymous_Access_To_Subprogram_Example procedure Add_Ten (I : in out Integer); @@ -1587,6 +1602,8 @@ We can declare subprogram parameters using anonymous types: I := I + 20; end Add_Twenty; +Finally, this is our test application: + .. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Anonymous_Access_To_Subprograms.Anonymous_Access_To_Subprogram_Example with Anonymous_Access_To_Subprogram; @@ -1602,15 +1619,18 @@ We can declare subprogram parameters using anonymous types: -- to Proc end Show_Anonymous_Access_To_Subprograms; +Here, we get access to the :ada:`Add_Ten` procedure and pass it to the +:ada:`Proc` procedure. Note that this implementation is not different from the +:ref:`example for named access-to-subprogram types `. +In fact, in terms of usage, anonymous access-to-subprogram types are very +similar to named access-to-subprogram types. The major differences can be found +in the corresponding +:ref:`accessibility rules `. .. admonition:: In the Ada Reference Manual - :arm22:`3.10 Access Types <3-10>` -.. todo:: - - Complete section! - .. _Adv_Ada_Accessibility_Rules_Anonymous_Access_To_Subprograms: From 1eb64c3e11c322020cad4603642544b3a08c2bc9 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:25:54 +0200 Subject: [PATCH 11/14] Adding subsection with examples of anonymous access-to-subprograms --- .../anonymous_access_types.rst | 300 ++++++++++++++++++ 1 file changed, 300 insertions(+) diff --git a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst index ffb51886a..de8d38a2b 100644 --- a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst @@ -1632,6 +1632,306 @@ in the corresponding - :arm22:`3.10 Access Types <3-10>` +Examples of anonymous access-to-subprogram usage +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the section about +:ref:`named access-to-subprogram types `, we've +seen a couple of different usages for those types. In all those examples +we discussed, we could instead have used anonymous access-to-subprogram types. +Let's see a code example that illustrates that: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Anonymous_Access_To_Subprograms.Anonymous_Access_To_Subprogram_Example + + package All_Anonymous_Access_To_Subprogram is + + -- + -- Anonymous access-to-subprogram as + -- subprogram parameter: + -- + procedure Proc + (P : access procedure (I : in out Integer)); + + -- + -- Anonymous access-to-subprogram in + -- array type declaration: + -- + type Access_To_Procedure_Array is + array (Positive range <>) of + access procedure (I : in out Integer); + + protected type Protected_Integer is + + procedure Mult_Ten; + + procedure Mult_Twenty; + + private + I : Integer := 1; + end Protected_Integer; + + -- + -- Anonymous access-to-subprogram as + -- component of a record type. + -- + type Rec_Access_To_Procedure is record + AP : access procedure (I : in out Integer); + end record; + + -- + -- Anonymous access-to-subprogram as + -- discriminant: + -- + type Rec_Access_To_Procedure_Discriminant + (AP : access procedure + (I : in out Integer)) is + record + I : Integer := 0; + end record; + + procedure Process + (R : in out + Rec_Access_To_Procedure_Discriminant); + + generic + type T is private; + + -- + -- Anonymous access-to-subprogram as + -- formal parameter: + -- + Proc_T : access procedure + (Element : in out T); + procedure Gen_Process (Element : in out T); + + end All_Anonymous_Access_To_Subprogram; + + with Ada.Text_IO; use Ada.Text_IO; + + package body All_Anonymous_Access_To_Subprogram is + + procedure Proc + (P : access procedure (I : in out Integer)) + is + I : Integer := 0; + begin + Put_Line + ("Calling procedure for Proc..."); + P (I); + Put_Line ("Finished."); + end Proc; + + procedure Process + (R : in out + Rec_Access_To_Procedure_Discriminant) + is + begin + Put_Line + ("Calling procedure for" + & " Rec_Access_To_Procedure_Discriminant" + & " type..."); + R.AP (R.I); + Put_Line ("Finished."); + end Process; + + procedure Gen_Process (Element : in out T) is + begin + Put_Line + ("Calling procedure for Gen_Process..."); + Proc_T (Element); + Put_Line ("Finished."); + end Gen_Process; + + protected body Protected_Integer is + + procedure Mult_Ten is + begin + I := I * 10; + end Mult_Ten; + + procedure Mult_Twenty is + begin + I := I * 20; + end Mult_Twenty; + + end Protected_Integer; + + end All_Anonymous_Access_To_Subprogram; + +In the :ada:`All_Anonymous_Access_To_Subprogram` package, we see examples of +anonymous access-to-subprogram types: + +- as a subprogram parameter; + +- in an array type declaration; + +- as a component of a record type; + +- as a record type discriminant; + +- as a formal parameter of a generic procedure. + +Let's implement a test application that makes use of this package: + +.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Anonymous_Access_Types.Anonymous_Access_To_Subprograms.Anonymous_Access_To_Subprogram_Example + + with Ada.Text_IO; use Ada.Text_IO; + + with Add_Ten; + with Add_Twenty; + + with All_Anonymous_Access_To_Subprogram; + use All_Anonymous_Access_To_Subprogram; + + procedure Show_Anonymous_Access_To_Subprograms is + -- + -- Anonymous access-to-subprogram as + -- an object: + -- + P : access procedure (I : in out Integer); + + -- + -- Array of anonymous access-to-subprogram + -- components + -- + PA : constant + Access_To_Procedure_Array (1 .. 2) := + (Add_Ten'Access, + Add_Twenty'Access); + + -- + -- Anonymous array of anonymous + -- access-to-subprogram components: + -- + PAA : constant + array (1 .. 2) of access + procedure (I : in out Integer) := + (Add_Ten'Access, + Add_Twenty'Access); + + -- + -- Record with anonymous + -- access-to-subprogram components: + -- + RA : constant Rec_Access_To_Procedure := + (AP => Add_Ten'Access); + + -- + -- Record with anonymous + -- access-to-subprogram discriminant: + -- + RD : Rec_Access_To_Procedure_Discriminant + (AP => Add_Twenty'Access) := + (AP => Add_Twenty'Access, I => 0); + + -- + -- Generic procedure with formal anonymous + -- access-to-subprogram: + -- + procedure Process_Integer is new + Gen_Process (T => Integer, + Proc_T => Add_Twenty'Access); + + -- + -- Object (APP) of anonymous + -- access-to-protected-subprogram: + -- + PI : Protected_Integer; + APP : constant access protected procedure := + PI.Mult_Ten'Access; + + Some_Int : Integer := 0; + begin + Put_Line ("Some_Int: " & Some_Int'Image); + + -- + -- Using object of + -- anonymous access-to-subprogram type: + -- + P := Add_Ten'Access; + Proc (P); + P (Some_Int); + + P := Add_Twenty'Access; + Proc (P); + P (Some_Int); + + Put_Line ("Some_Int: " & Some_Int'Image); + + -- + -- Using array with component of + -- anonymous access-to-subprogram type: + -- + Put_Line + ("Calling procedure from PA array..."); + + for I in PA'Range loop + PA (I) (Some_Int); + Put_Line ("Some_Int: " & Some_Int'Image); + end loop; + + Put_Line ("Finished."); + + Put_Line + ("Calling procedure from PAA array..."); + + for I in PA'Range loop + PAA (I) (Some_Int); + Put_Line ("Some_Int: " & Some_Int'Image); + end loop; + + Put_Line ("Finished."); + + Put_Line ("Some_Int: " & Some_Int'Image); + + -- + -- Using record with component of + -- anonymous access-to-subprogram type: + -- + RA.AP (Some_Int); + Put_Line ("Some_Int: " & Some_Int'Image); + + -- + -- Using record with discriminant of + -- anonymous access-to-subprogram type: + -- + Process (RD); + Put_Line ("RD.I: " & RD.I'Image); + + -- + -- Using procedure instantiated with + -- formal anonymous access-to-subprogram: + -- + Process_Integer (Some_Int); + Put_Line ("Some_Int: " & Some_Int'Image); + + -- + -- Using object of anonymous + -- access-to-protected-subprogram type: + -- + APP.all; + end Show_Anonymous_Access_To_Subprograms; + +In the :ada:`Show_Anonymous_Access_To_Subprograms` procedure, we see examples +of anonymous access-to-subprogram types in: + +- in objects (:ada:`P`) and (:ada:`APP`); + +- in arrays (:ada:`PA` and :ada:`PAA`); + +- in records (:ada:`RA` and :ada:`RD`); + +- in the binding to a formal parameter (:ada:`Proc_T`) of an instantiated + procedure (:ada:`Process_Integer`); + +- as a parameter of a procedure (:ada:`Proc`). + +Because we already discussed all these usages in the section about +:ref:`named access-to-subprogram types `, we +won't repeat this discussion here. If anything in this code example is still +unclear to you, make sure to revisit that section from the previous chapter. + + .. _Adv_Ada_Accessibility_Rules_Anonymous_Access_To_Subprograms: Accessibility Rules and Anonymous Access-To-Subprograms From 4a29347483012e8c793929b7e26a21eb3269a999 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:26:51 +0200 Subject: [PATCH 12/14] Adding subsection on applications of anonymous access-to-subprograms --- .../anonymous_access_types.rst | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst index de8d38a2b..33e669fa6 100644 --- a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst @@ -1932,6 +1932,32 @@ won't repeat this discussion here. If anything in this code example is still unclear to you, make sure to revisit that section from the previous chapter. +Application of anonymous access-to-subprogram types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In general, there isn't much that speaks against using anonymous +access-to-subprogram types. We can say, for example, that they're much more +useful than +:ref:`anonymous access-to-objects types `, +which have +:ref:`many drawbacks ` |mdash| +as we discussed earlier. + +There isn't much to be concerned when using anonymous access-to-subprogram +types. For example, we cannot allocate or deallocate a subprogram. As a +consequence, we won't have storage management issues affecting these types +because the access to those subprograms will always be available and no +memory leak can occur. + +Also, anonymous access-to-subprogram types can be easier to use than named +access-to-subprogram types because of their less strict +:ref:`accessibility rules `. +Some of the accessibility issues we might encounter when using named +access-to-subprogram types can be solved by declaring them as anonymous types. +(We discuss the accessibility rules of anonymous access-to-subprogram types in +the next section.) + + .. _Adv_Ada_Accessibility_Rules_Anonymous_Access_To_Subprograms: Accessibility Rules and Anonymous Access-To-Subprograms From ce89248e90e85149fdd0a41d59299b6fe578f3b0 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 22 Sep 2023 18:37:45 +0200 Subject: [PATCH 13/14] Editorial change: correcting references --- .../parts/resource_management/anonymous_access_types.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst index 33e669fa6..a18cbc044 100644 --- a/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/anonymous_access_types.rst @@ -1625,7 +1625,7 @@ Here, we get access to the :ada:`Add_Ten` procedure and pass it to the In fact, in terms of usage, anonymous access-to-subprogram types are very similar to named access-to-subprogram types. The major differences can be found in the corresponding -:ref:`accessibility rules `. +:ref:`accessibility rules `. .. admonition:: In the Ada Reference Manual @@ -1951,7 +1951,7 @@ memory leak can occur. Also, anonymous access-to-subprogram types can be easier to use than named access-to-subprogram types because of their less strict -:ref:`accessibility rules `. +:ref:`accessibility rules `. Some of the accessibility issues we might encounter when using named access-to-subprogram types can be solved by declaring them as anonymous types. (We discuss the accessibility rules of anonymous access-to-subprogram types in From c84178786d135c77d3e0d13948e8e8cc8ba73606 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 6 Oct 2023 15:07:52 +0200 Subject: [PATCH 14/14] Minor improvements --- .../advanced-ada/parts/resource_management/access_types.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/courses/advanced-ada/parts/resource_management/access_types.rst b/content/courses/advanced-ada/parts/resource_management/access_types.rst index 4a2b36c55..ff9229593 100644 --- a/content/courses/advanced-ada/parts/resource_management/access_types.rst +++ b/content/courses/advanced-ada/parts/resource_management/access_types.rst @@ -3668,9 +3668,9 @@ procedure. We can use an access-to-subprogram object either as the actual parameter of a subprogram call, or in a subprogram call. In the code example, we're passing -:ada:`P` as the actual parameter of the :ada:`Proc` procedure -(in the :ada:`Proc (P)` calls), and we're calling the subprogram assigned to -:ada:`P` (in the :ada:`P (Some_Int)` calls). +:ada:`P` as the actual parameter of the :ada:`Proc` procedure in the +:ada:`Proc (P)` calls. Also, we're calling the subprogram assigned to +(designated by the current value of) :ada:`P` in the :ada:`P (Some_Int)` calls. Components of access-to-subprogram type