!standard 5.5.2(2/3) 18-03-29 AI12-0268-1/01 !standard 5.5.2(5/4) !standard 5.5.2(7/3) !class Amendment 18-03-29 !status work item 18-03-29 !status received 18-03-22 !priority Medium !difficulty Medium !subject Automatic instantiation for generic formal parameters !summary Automatic instantiation is added to generic formal parameters. !problem Every Ada generic instantiation needs to be named and declared. When an instantiation is created solely to be passed to another generic instantiation, this requires picking a name for an instantiation that isn't intended to be visible to any other code. !proposal We can have default generic-parameters which are automatically instantiated. The formal syntax for the above method would essentially combine the instantiation syntax into the generic formal parameter syntax after USE, thereby altering: 12.6 (2/2) — formal_subprogram_declaration ::= formal_concrete_subprogram_declaration | formal_abstract_subprogram_declaration | formal_default_subprogram_declaration and adding formal_default_subprogram_declaration ::= use [overriding_indicator] procedure defining_program_unit_name is new generic_procedure_name [generic_actual_part] [aspect_specification]; | use [overriding_indicator] function defining_designator is new generic_function_name [generic_actual_part] [aspect_specification]; Because, as a default itself, the inclusion of “is null”, “is <>”, and “is default_name” are meaningless. (Note: syntax taken from 12.3 (2/3), it could probably be cleaned up.) 12.7 (2/3) — formal_package_declaration ::= with package defining_identifier is new generic_package_name formal_package_actual_part [aspect_specification]; | use package defining_identifier is new generic_package_name formal_package_actual_part [aspect_specification]; Which I think would work syntactically. !wording ** TBD. !discussion ** TBD. !examples For example, given our current abilities with Ada’s generics and defaults we could say: Generic Type Some_Type is private; Procedure Generic_Swap( A, B : in out Some_Type ); Generic Type Element is private; Type Index is (<>); Type Array_Type is Array(Index Range <>) of Element; With Procedure Swap(A, B : in out Element) is <>; Procedure Generic_Sort( Input : in out Array_Type ); However, this requires an instantiation of Generic_Swap and results in something similar to the following: -- Types. Type Integer_Vector is Array(Integer range <>) of Integer; -- Instantiations. Procedure Swap is new Generic_Swap( Integer ); Procedure Sort is new Generic_Sort( Swap => Swap, -- This line could be deleted. Element => Integer, Index => Integer, Array_Type => Integer_Vector ); With our current defaulting methods, we could eliminate the Swap parameter of the instantiation Generic_Sort, but we have enough information in the definition of Generic_Sort that we could eliminate both it and the currently required instantiation of Generic_Swap. So, with proper syntax, we could say something like: Generic Type Element is private; Type Index is (<>); Type Array_Type is Array(Index Range <>) of Element; Use Procedure Swap is new Generic_Swap(Some_Type => Element); Procedure Generic_Sort( Input : in out Array_Type ); This also works with Packages and given the following — Generic Type Element(<>) is private; Package Generic_Stack is -- ... End Generic_Stack; Generic Type PostScript_Object(<>) is private; Type PostScript_Float is private; Type PostScript_Context is private; with Package Object_Stack is new Generic_Stack(PostScript_Object); with Package Float_Stack is new Generic_Stack(PostScript_Float); with Package Context_Stack is new Generic_Stack(PostScript_Context); Package Generic_PostScript_VM is -- ... end Generic_PostScript_VM; -- Type Stubs Type PS_Object is tagged null record; Type Real is new Interfaces.IEEE_Float_64; Type Context is null record; we could reduce the required instantiations of — -- Instantiations. Package Object_Stack is new Generic_Stack(PS_Object'Class); Package Real_Stack is new Generic_Stack(Real); Package Context_Stack is new Generic_Stack(Context); Package PostScript_VM is new Generic_PostScript_VM( PostScript_Object => PS_Object'Class, PostScript_Float => Real, PostScript_Context => Context, Object_Stack => Object_Stack, Float_Stack => Real_Stack, Context_Stack => Context_Stack ); to: -- Instantiations. Package PostScript_VM is new Generic_PostScript_VM( PostScript_Object => PS_Object'Class, PostScript_Float => Real, PostScript_Context => Context ); simply by replacing the WITH by USE in the definition. !ASIS [Not sure. It seems like some new capabilities might be needed, but I didn't check - Editor.] !ACATS test ACATS B- and C-Tests are needed to check that the new capabilities are supported. !appendix From: Edward Fish Sent: Thursday, March 22, 2018 1:48 PM While this AI (AI12-0205-1 - ED) seems concerned with defaults of object-parameters (particularly IN OUT), there are other advantages to default-parameters that can be had. In particular, we can have default generic-parameters which are automatically instantiated — thereby eliminating the need for one-off instantiations which, in turn, would simplify the code of current Ada projects (particularly at the library level*). For example, given our current abilities with Ada’s generics and defaults we could say: Generic Type Some_Type is private; Procedure Generic_Swap( A, B : in out Some_Type ); Generic Type Element is private; Type Index is (<>); Type Array_Type is Array(Index Range <>) of Element; With Procedure Swap(A, B : in out Element) is <>; Procedure Generic_Sort( Input : in out Array_Type ); However, this requires an instantiation of Generic_Swap and results in something similar to the following: -- Types. Type Integer_Vector is Array(Integer range <>) of Integer; -- Instantiations. Procedure Swap is new Generic_Swap( Integer ); Procedure Sort is new Generic_Sort( Swap => Swap, -- This line could be deleted. Element => Integer, Index => Integer, Array_Type => Integer_Vector ); With our current defaulting methods, we could eliminate the Swap parameter of the instantiation Generic_Sort, but we have enough information in the definition of Generic_Sort that we could eliminate both it and the currently required instantiation of Generic_Swap. So, with proper syntax, we could say something like: Generic Type Element is private; Type Index is (<>); Type Array_Type is Array(Index Range <>) of Element; Use Procedure Swap is new Generic_Swap(Some_Type => Element); Procedure Generic_Sort( Input : in out Array_Type ); The above could be said to move the instantiation into the formal-parameter list, and is more inline with how generic packages may currently be linked/tied together (in eg signature-packages), and the instantiation of Generic_Swap can now be elided into the instantiation of Generic_Sort, cleaning out the previous namespace a bit, as well as [possibly] offering public access to the instantiation via Generic_Sort.Swap. This also works with Packages and given the following — Generic Type Element(<>) is private; Package Generic_Stack is -- ... End Generic_Stack; Generic Type PostScript_Object(<>) is private; Type PostScript_Float is private; Type PostScript_Context is private; with Package Object_Stack is new Generic_Stack(PostScript_Object); with Package Float_Stack is new Generic_Stack(PostScript_Float); with Package Context_Stack is new Generic_Stack(PostScript_Context); Package Generic_PostScript_VM is -- ... end Generic_PostScript_VM; -- Type Stubs Type PS_Object is tagged null record; Type Real is new Interfaces.IEEE_Float_64; Type Context is null record; we could reduce the required instantiations of — -- Instantiations. Package Object_Stack is new Generic_Stack(PS_Object'Class); Package Real_Stack is new Generic_Stack(Real); Package Context_Stack is new Generic_Stack(Context); Package PostScript_VM is new Generic_PostScript_VM( PostScript_Object => PS_Object'Class, PostScript_Float => Real, PostScript_Context => Context, Object_Stack => Object_Stack, Float_Stack => Real_Stack, Context_Stack => Context_Stack ); to: -- Instantiations. Package PostScript_VM is new Generic_PostScript_VM( PostScript_Object => PS_Object'Class, PostScript_Float => Real, PostScript_Context => Context ); simply by replacing the WITH by USE in the definition. Additionally, this defaulting should obviously be able to be overridden, so even in the USE form the more verbose instantiations above would still be valid. The formal syntax for the above method would essentially combine the instantiation syntax into the generic formal parameter syntax after USE, thereby altering: 12.6 (2/2) — formal_subprogram_declaration ::= formal_concrete_subprogram_declaration | formal_abstract_subprogram_declaration | formal_default_subprogram_declaration and adding formal_default_subprogram_declaration ::= use [overriding_indicator] procedure defining_program_unit_name is new generic_procedure_name [generic_actual_part] [aspect_specification]; | use [overriding_indicator] function defining_designator is new generic_function_name [generic_actual_part] [aspect_specification]; Because, as a default itself, the inclusion of “is null”, “is <>”, and “is default_name” are meaningless. (Note: syntax taken from 12.3 (2/3), it could probably be cleaned up.) 12.7 (2/3) — formal_package_declaration ::= with package defining_identifier is new generic_package_name formal_package_actual_part [aspect_specification]; | use package defining_identifier is new generic_package_name formal_package_actual_part [aspect_specification]; Which I think would work syntactically. * For Ada projects using GNAT in particular, which requires separate files for every library-level instantiation, the complexity-savings in the number of files that have to be maintained could be substantial for a project that heavily uses generics. **************************************************************** From: Randy Brukardt Sent: Thursday, March 29, 2018 9:25 PM > While this AI seems concerned with defaults of object-parameters > (particularly IN OUT), there are other advantages to > default-parameters that can be had. We decided to give this it's own AI. > ... In > particular, we can have default generic-parameters which are > automatically instantiated — thereby eliminating the need for one-off > instantiations which, in turn, would simplify the code of current Ada > projects (particularly at the library level*). > > For example, given our current abilities with Ada’s generics and > defaults we could say: > > Generic > Type Some_Type is private; > Procedure Generic_Swap( A, B : in out Some_Type ); > > Generic > Type Element is private; > Type Index is (<>); > Type Array_Type is Array(Index Range <>) of Element; > With Procedure Swap(A, B : in out Element) is <>; > Procedure Generic_Sort( Input : in out Array_Type ); For me personally, there's little chance of any useful generics lying around. All of the one's I've used are heavily tailored for a particular purpose. I can imagine it happens to others. However, there is a related problem that hits me all the time, and this generic sort shows it well. And that is the need to declare one-off subprograms to use with generics. I'd end up with something like: procedure Int_Swap (Left, Right : in out Integer) is Temp : Integer; begin Temp := Left; Left := Right; Right := Temp; end Int_Swap; procedure Sort is new Generic_Sort( Swap => Int_Swap, Element => Integer, Index => Integer, Array_Type => Integer_Vector); But if this is a specification, the body can't even be here, so now you have to declare a body somewhere, too. This is probably one of the few cases where anonymous anything would be helpful, but none of the proposals actually allow that. A similar thought seems to hold for this idea; it seems more likely to be valuable in the instance rather than as a default. Perhaps that's just my usage patterns. **************************************************************** From: Edward Fish Sent: Friday, March 30, 2018 12:35 PM >> While this AI seems concerned with defaults of object-parameters >> (particularly IN OUT), there are other advantages to >> default-parameters that can be had. > We decided to give this it's own AI. Interesting; is that good? Though I did think it was somewhat pertinent to the formal OUT & IN OUT parameter-defaults; that is, the same idea could be applied to put the actual parameter into the scope that the actual instance uses unless overridden by the parameter-association of the instantiation. This is to say that: Generic Param : out Integer := 21; -- Or whatever IN OUT /OUT mode-defaulting syntax is chosen. Package Example_Pkg is Procedure Operation; End Example_Pkg; Package Body Example_Pkg is Procedure Operation is Begin Param := 5; End Operation; End Example_Pkg; -- ... ACTUAL_EXAMPLE: Declare Lights : Integer := 4; -- THERE. ARE. FOUR. LIGHTS! Package Ex_Init is new Example( Lights ); Begin Ex_Init.Operation; -- Now there are five lights. End ACTUAL_EXAMPLE; -- ACTUAL_EXAMPLE could be replaced by: REDUCED_EXAMPLE: Declare Package Ex_Init is new Example; -- This creates Ex_Init.Param, and sets its value to 21. Begin Ex_Init.Operation; -- Now Ex_Init.Param is 5. End REDUCED_EXAMPLE; The biggest problem is that this creates aliasing where ACTUAL_EXAMPLE's Lights and Ex_init.Param refer to the same thing. Though I think that this could be handled by treating Ex_Init.Param as a RENAME of Lights for analysis purposes. (Though perhaps the mode-restriction would invalidate that interpretation/notion; I don't have the static analysis expertise to say.) >> ... In >> particular, we can have default generic-parameters which are >> automatically instantiated - thereby eliminating the need for one-off >> instantiations which, in turn, would simplify the code of current Ada >> projects (particularly at the library level*). >> >> For example, given our current abilities with Ada's generics and >> defaults we could say: >> >> Generic >> Type Some_Type is private; >> Procedure Generic_Swap( A, B : in out Some_Type ); >> >> Generic >> Type Element is private; >> Type Index is (<>); >> Type Array_Type is Array(Index Range <>) of Element; >> With Procedure Swap(A, B : in out Element) is <>; >> Procedure Generic_Sort( Input : in out Array_Type ); > For me personally, there's little chance of any useful generics lying > around. All of the one's I've used are heavily tailored for a > particular purpose. I cam imagine it happens to others. > > However, there is a related problem that hits me all the time, and > this generic sort shows it well. And that is the need to declare > one-off subprograms to use with generics. I'd end up with something like: > > procedure Int_Swap (Left, Right : in out Integer) is > Temp : Integer; > begin > Temp := Left; > Left := Right; > Right := Temp; > end Int_Swap; > > procedure Sort is new Generic_Sort( > Swap => Int_Swap, > Element => Integer, > Index => Integer, > Array_Type => Integer_Vector); > > But if this is a specification, the body can't even be here, so now > you have to declare a body somewhere. > > This is probably one of the few cases where anonymous anything would > be helpful, but none of the proposals actually allow that. What anonymous thing do you want here? This proposal, so far, doesn't use anything anonymously and instead makes use of the actual instantiation to automatically chain instantiation of non-overriding/non-specified defaults into its own namespace... so there's nothing anonymous that I can see there. / Or am I misunderstanding what you're meaning? > A similar thought seems to hold for this idea; it seems more likely to > be valuable in the instance rather than as a default. > > Perhaps that's just my usage patterns. Are the two (default vs. instance) necessarily opposed? It seems obvious to me they're related, just as a call to a Function Image( X : Integer; Alignment : Justification := Right ) return String {given TYPE Justification IS (Left, Right, Center);} is related to the default by its usage/non-usage: "Text : String := Image(23, Left);" vs "Text : String := Image(23);". It's also worth noting that there's a bit of a difference between subprograms and packages as formal parameters for generics; as packages the parameter needs to be a generic. as a subprogram they cannot be. While I typically like Ada's generic faculties, and they tend to be much better than the now-typical types-as-parameters generics, this always seemed a bit odd to me. **************************************************************** From: Randy Brukardt Sent: Friday, March 30, 2018 4:36 PM > Interesting; is that good? It's related to the existing suggestion but sufficiently different and complex that it seemed worth considering separately. AI12-0205-1 is in the "simple" category, I'd like to keep it there, and anything to do with instantiations is not simple. ... > > However, there is a related problem that hits me all the time, and > > this generic sort shows it well. And that is the need to declare > > one-off subprograms to use with generics. I'd end up with something like: > > > > procedure Int_Swap (Left, Right : in out Integer) is > > Temp : Integer; > > begin > > Temp := Left; > > Left := Right; > > Right := Temp; > > end Int_Swap; > > > > procedure Sort is new Generic_Sort( > > Swap => Int_Swap, > > Element => Integer, > > Index => Integer, > > Array_Type => Integer_Vector); > > > > But if this is a specification, the body can't even be here, so now > > you have to declare a body somewhere. > > > > This is probably one of the few cases where anonymous anything would > > be helpful, but none of the proposals actually allow that. > What anonymous thing do you want here? Anonymous procedures and functions to pass to the instance for formal subprograms. Using the language-defined sort as an example: function Order (Left, Right : Float) return Boolean is (Func(Left) < Func(Right)); procedure My_Sort is new Ada.Containers.Generic_Array_Sort (Natural, Float, My_Array, Order); Here Order is a one-off function used only by My_Sort. It would be nice for it to be anonymous somehow: procedure My_Sort is new Ada.Containers.Generic_Array_Sort (Natural, Float, My_Array, function (Func(Left) < Func(Right))); > This proposal, so far, doesn't use anything anonymously and instead > makes use of the actual instantiation to automatically chain > instantiation of non-overriding/non-specified defaults into its own > namespace... so there's nothing anonymous that I can see there. / Or > am I misunderstanding what you're meaning? The automatic instance itself is anonymous to users of the enclosing instance - it does not have a name that its parts can be referenced through. For a subprogram, that probably doesn't matter (if you wanted to call it, you'd need a name, but then the instance would not have been a "1-off" in the first place). For a formal package though, you might want to access the contents when using the instance. For instance (ugh - way too many "instances" here!), imagine that you use your feature on a generic I/O package for a bounded string: generic Max : Positive; use package Bounded is new Ada.Strings.Bounded.Generic_Bounded_Length (Max); package Bounded_IO is procedure Put_Line (Item : in Bounded.Bounded_String); ... end Bounded_IO; So an instance could be: package Message_IO is new Bounded_IO (80); but here you don't have any way to name the type of the Bounded string (since formal packages are not visible outside of the instance, and the actual package was automatically instantiated without a name). You could try to give this package a name, but now the entire idea has become a lot more complicated because it is dragging in visibility issues - you are addingd a new kind of scope (it gets inserted inside of the instance implicitly by the instance, but only conditionally - its not there if the default isn't used). ****************************************************************