!standard A(15) 19-10-01 AI12-0302-1/03 !class Amendment 19-01-10 !status work item 19-01-10 !status received 19-01-10 !priority High !difficulty Medium !subject Default Global aspect for language-defined units !summary Language-defined units declared as Pure will be implicitly Global => null. Other (nongeneric) packages will have Global => synchronized in out . Generic packages will have Global => synchronized in out & 'Global & 'Global ... Subprograms that update the internal state of a "compound" object identified by an "in" parameter (e.g. File_Type and Generator), will have Global => overriding in out . IO routines that refer implicitly to Current_Input or Current_Output will have Global => in out Text_IO, meaning they will likely conflict with one another. !problem In the absence of a Global aspect, the default is "Global => in out all" unless a (generic) package is declared Pure. This is not consistent with the requirement of RM A(3/5) that language-defined (generic) packages be reentrant. !proposal For language-defined units declared Pure, we will have the implicit Global => null. For other nongeneric packages, we will insert an explicit: Global => synchronized in out where is the name of the package for which the Global aspect is specified. For generic packages, the Global aspects of appropriate generic formals will be "concatenated" to the "synchronized in out ". For library (generic) subprograms that are not merely renames of some subprogram declared elsewhere, the will refer to the parent package (or generic package) of the library (generic) subprogram, plus appropriate Global aspects of generic formal parameters. Below are two lists of the language-defined units. The first list is those declared Pure. The second list is of those not declared Pure. We have reviewed the second list and made certain that "Global => synchronized in out " is appropriate for each, possibly with Global aspects for generic formals concatenated. Some will have individual operations that can be specified as Global => null, if their result is purely a function of their inputs. And some, in particular in the I/O packages, will need to indicate their use of an unknown, unsynchronized global corresponding to Current_Input or Current_Output, as explained in RM A(3.1/4). For these, ideally we could write something like: Global => (in out Current_Input.all, synchronized in out Text_IO) or Global => (in out Current_Output.all, synchronized in out Text_IO) but alas, Current_Input and Current_Output are function calls, and do not statically denote an object. So we are relegated to simply: Global => in out Text_IO presuming that the associated state is all kept in a collection that is part of Text_IO, but is *not* synchronized. This would mean that two concurrent subprogram calls using either Current_Input or Current_Output would be considered to conflict. A more general problem has to do with parameters that are clearly "handles" or equivalent on a "compound" object, as defined in AI12-0240-6, such as a File_Type, random number Generator, or a task object. Even though they are passed as IN parameters, the subprogram can clearly update their associated state. One choice is to consider all of this state as residing, unsynchronized, in the associated package, as we did above for Current_Input and Current_Output, but that would be painful, since none of the, for example, File operations would be independent even when the Files designate distinct internal files. Instead, as part of AI12-0240-6, we have explicitly permitted the notion of "overriding" an IN mode with a mode that reflects the effect on the underlying "compound" object. Hence, Put and Get become: procedure Put (File : File_Type; Item : String) with Global => overriding in out File; procedure Get (File : File_Type; Item : out String) with Global => overriding in out File; Using the same approach, Random becomes: function Random(Gen : Generator) return Result_Subtype with Global => overriding in out Gen; Similarly, the various Reset procedures will have ... with Global => overriding in out Gen; Finally, we have functions that return generalized references into another object, e.g.: function Reference(Container : aliased in out Map; ...) return Reference_Type; How do we specify that the returned reference refers to some part of Container? Again, as part of AI12-0240-6, we have specified that if a function returns a type with Implicit_Dereference specified, the combination of the parameter mode of any aliased parameters and the Global aspect must indicate the set of objects to which the 'Result might designate. With this rule, we can specify Global => null on the above, because the "in out" mode of the Container parameter already captures the object designated by the result object. !wording So to summarize the wording, each library unit will have a well-defined Global aspect at the package level, being either implicitly "null" for pure library units, or explicitly "synchronized in out & 'Global & ..." for impure library units (see list of impure units below). And then within the impure units, individual subprograms may override this default with "null" when they are certain to have no side effects other than those represented by the modes of their formal parameters (not clear it is worth defining these at this stage), with "in [out] " when they refer to implicit state that is *not* synchronized, and "in [out] .all" when they refer to the variable state associated with a dereference of an IN parameter. OVERRIDING PARAMETER MODES Here are the details for subprograms with side effects that cannot use the default associated with the enclosing impure library unit (ignoring side-effect free subprograms for now): Within 13.11.4, Subpools: Modify Set_Pool_Of_Subpool, Allocate_From_Subpool to have: with Global => overriding in out Subpool; --- Within A.5.2, Discrete_Random and Float_Random: Modify Random, Reset to have with Global => overriding in out Gen; --- Within A.8.1, Sequential_IO: Modify Flush, Read, Write to have with Global => overriding in out File; --- Within A.8.4, Direct_IO: Modify Flush, Read, Write, Set_Index to have: with Global => overriding in out File; --- Within A.10.1, Text_IO: Modify current input/output versions of: Set_Line_Length, Set_Page_Length, New_Line, Skip_Line, New_Page, Skip_Page, Set_Col, Set_Line, Put, Get, Put_Line, Get_Line, Look_Ahead, Get_Immediate to have: with Global => in out Text_IO; Modify File_Type versions of Set_Line_Length, Set_Page_Length, New_Line, Skip_Line, New_Page, Skip_Page, Set_Col, Set_Line, Put, Get, Put_Line, Get_Line, Look_Ahead, Get_Immediate to have with Global => overriding in out File; Modify current input/output versions of: Line_Length, Page_Length, End_Of_Line, End_Of_Page, End_Of_File, Col, Line, Page to have with Global => in Text_IO; --- Within A.12.1, Stream_IO: Modify Read, Write, Set_Index to have: with Global => overriding in out File; GLOBAL ASPECTS ON GENERIC UNITs As a general rule, all language-defined generic units will include "'Global & 'Global & ..." as part of their unit-level Global aspect. For pure generic units, that is all that will appear. For impure generic units, this will be prefixed with "synchronized in out & ". Here is a list of exceptions to this general rule: Generic_Elementary_Functions, Generic_Complex_Types, Complex_Elementary_Functions, Generic_Real_Arrays, and Generic_Complex_Arrays can have simply: Global => null because the base subtype of the formal "Real" subtype is what is used, and the base subtype has any predicates stripped off. --- --------------- The Pure group: --------------- Standard -- A.1 Ada -- A.2 Assertions 11.4.2 Characters -- A.3.1 Conversions -- A.3.4 Handling -- A.3.2 Latin_1 -- A.3.3 Containers -- A.18.1 Bounded_Doubly_Linked_Lists -- A.18.20 Bounded_Hashed_Maps -- A.18.21 Bounded_Hashed_Sets -- A.18.23 Bounded_Multiway_Trees -- A.18.25 Bounded_Ordered_Maps -- A.18.22 Bounded_Ordered_Sets -- A.18.24 Bounded_Vectors -- A.18.19 Generic_Array_Sort -- A.18.26 Generic_Constrained_Array_Sort -- A.18.26 Generic_Sort -- A.18.26 Synchronized_Queue_Interfaces -- A.18.27 Decimal -- F.2 IO_Exceptions -- A.13 Iterator_Interfaces -- 5.5.1 Locales -- A.19 Numerics -- A.5 Big_Numbers -- A.5.5 Complex_Arrays -- G.3.2 Complex_Elementary_Functions -- G.1.2 Complex_Types -- G.1.1 Elementary_Functions -- A.5.1 Generic_Complex_Arrays -- G.3.2 Generic_Complex_Elementary_Functions -- G.1.2 Generic_Complex_Types -- G.1.1 Generic_Elementary_Functions -- A.5.1 Generic_Real_Arrays -- G.3.1 Real_Arrays -- G.3.1 Streams -- 13.13.1 Storage -- 13.13.1 Strings -- A.4.1 Equal_Case_Insensitive -- A.4.10 Hash -- A.4.9 Hash_Case_Insensitive -- A.4.9 Less_Case_Insensitive -- A.4.10 Maps -- A.4.2 Constants -- A.4.6 UTF_Encoding -- A.4.11 Conversions -- A.4.11 Strings -- A.4.11 Wide_Strings -- A.4.11 Wide_Wide_Strings -- A.4.11 Wide_Equal_Case_Insensitive -- A.4.7 Wide_Hash -- A.4.7 Wide_Hash_Case_Insensitive -- A.4.7 Wide_Wide_Equal_Case_Insensitive -- A.4.8 Wide_Wide_Hash -- A.4.8 Wide_Wide_Hash_Case_Insensitive -- A.4.8 Unchecked_Conversion -- 13.9 Unchecked_Deallocate_Subpool -- 13.11.5 Unchecked_Deallocation -- 13.11.2 Wide_Characters -- A.3.1 Handling -- A.3.5 Wide_Wide_Characters -- A.3.1 Handling -- A.3.6 Interfaces -- B.2 C -- B.3 COBOL -- B.4 Fortran -- B.5 System -- 13.7 Atomic_Operations -- C.6.1 Arithmetic -- C.6.4 Exchange -- C.6.2 Test_And_Set -- C.6.2 Storage_Elements -- 13.7.1 ----------------- The impure group: ----------------- [Ada] Asynchronous_Task_Control -- D.11 Calendar -- 9.6 Arithmetic -- 9.6.1 Formatting -- 9.6.1 Time_Zones -- 9.6.1 Command_Line -- A.15 Complex_Text_IO -- G.1.3 [Containers] Bounded_Indefinite_Holders -- A.18.32 Bounded_Priority_Queues -- A.18.31 Bounded_Synchronized_Queues -- A.18.29 Doubly_Linked_Lists -- A.18.3 Hashed_Maps -- A.18.5 Hashed_Sets -- A.18.8 Indefinite_Doubly_Linked_Lists -- A.18.12 Indefinite_Hashed_Maps -- A.18.13 Indefinite_Hashed_Sets -- A.18.15 Indefinite_Holders -- A.18.18 Indefinite_Multiway_Trees -- A.18.17 Indefinite_Ordered_Maps -- A.18.14 Indefinite_Ordered_Sets -- A.18.16 Indefinite_Vectors -- A.18.11Standard (...continued) Multiway_Trees -- A.18.10 Ordered_Maps -- A.18.6 Ordered_Sets -- A.18.9 Unbounded_Priority_Queues -- A.18.30 Unbounded_Synchronized_Queues -- A.18.28 Vectors -- A.18.2 Direct_IO -- A.8.4 Directories -- A.16 Hierarchical_File_Names -- A.16.1 Information -- A.16 Dispatching -- D.2.1 EDF -- D.2.6 Non_Preemptive -- D.2.4 Round_Robin -- D.2.5 Dynamic_Priorities -- D.5.1 Environment_Variables -- A.17 Exceptions -- 11.4.1 Execution_Time -- D.14 Group_Budgets -- D.14.2 Interrupts -- D.14.3 Timers -- D.14.1 Finalization -- 7.6 Float_Text_IO -- A.10.9 Float_Wide_Text_IO -- A.11 Float_Wide_Wide_Text_IO -- A.11 Integer_Text_IO -- A.10.8 Integer_Wide_Text_IO -- A.11 Integer_Wide_Wide_Text_IO -- A.11 Interrupts -- C.3.2 Names -- C.3.2 [Numerics] Big_Integers -- A.5.6 Big_Reals -- A.5.7 Discrete_Random -- A.5.2 Float_Random -- A.5.2 Real_Time -- D.8 Timing_Events -- D.15 Sequential_IO -- A.8.1 Storage_IO -- A.9 [Streams] Bounded -- 13.13.1 Stream_IO -- A.12.1 Unbounded -- 13.13.1 [Strings] Bounded -- A.4.4 Equal_Case_Insensitive -- A.4.10 Hash -- A.4.9 Hash_Case_Insensitive -- A.4.9 Less_Case_Insensitive -- A.4.10 Fixed -- A.4.3 Equal_Case_Insensitive -- A.4.10 Hash -- A.4.9 Hash_Case_Insensitive -- A.4.9 Less_Case_Insensitive -- A.4.10 Unbounded -- A.4.5 Equal_Case_Insensitive -- A.4.10 Hash -- A.4.9 Hash_Case_Insensitive -- A.4.9 Less_Case_Insensitive -- A.4.10 Wide_Bounded -- A.4.7 Wide_Equal_Case_Insensitive -- A.4.7 Wide_Hash -- A.4.7 Wide_Hash_Case_Insensitive -- A.4.7 Wide_Fixed -- A.4.7 Wide_Equal_Case_Insensitive -- A.4.7 Wide_Hash -- A.4.7 Wide_Hash_Case_Insensitive -- A.4.7 Wide_Maps -- A.4.7 Wide_Constants -- A.4.7 Wide_Unbounded -- A.4.7 Wide_Equal_Case_Insensitive -- A.4.7 Wide_Hash -- A.4.7 Wide_Hash_Case_Insensitive -- A.4.7 Wide_Wide_Bounded -- A.4.8 Wide_Wide_Equal_Case_Insensitive -- A.4.8 Wide_Wide_Hash -- A.4.8 Wide_Wide_Hash_Case_Insensitive -- A.4.8 Wide_Wide_Fixed -- A.4.8 Wide_Wide_Equal_Case_Insensitive -- A.4.8 Wide_Wide_Hash -- A.4.8 Wide_Wide_Hash_Case_Insensitive -- A.4.8 Wide_Wide_Maps -- A.4.8 Wide_Wide_Constants -- A.4.8 Wide_Wide_Unbounded -- A.4.8 Wide_Wide_Equal_Case_Insensitive -- A.4.8 Wide_Wide_Hash -- A.4.8 Wide_Wide_Hash_Case_Insensitive -- A.4.8 Synchronous_Barriers -- D.10.1 Synchronous_Task_Control -- D.10 EDF -- D.10 Tags -- 3.9 Generic_Dispatching_Constructor -- 3.9 Task_Attributes -- C.7.2 Task_Identification -- C.7.1 Task_Termination -- C.7.3 Text_IO -- A.10.1 Bounded_IO -- A.10.11 Complex_IO -- G.1.3 Editing -- F.3.3 Text_Streams -- A.12.2 Unbounded_IO -- A.10.12 Unchecked_Deallocate_Subpool -- 13.11.5 Unchecked_Deallocation -- 13.11.2 Wide_Command_Line -- A.15.1 Wide_Directories -- A.16.2 Wide_Environment_Variables -- A.17.1 Wide_Text_IO -- A.11 Complex_IO -- G.1.4 Editing -- F.3.4 Text_Streams -- A.12.3 Wide_Bounded_IO -- A.11 Wide_Unbounded_IO -- A.11 Wide_Wide_Text_IO -- A.11 Complex_IO -- G.1.5 Editing -- F.3.5 Text_Streams -- A.12.4 Wide_Wide_Bounded_IO -- A.11 Wide_Wide_Unbounded_IO -- A.11 Wide_Wide_Command_Line -- A.15.1 Wide_Wide_Directories -- A.16.2 Wide_Wide_Environment_Variables -- A.17.1 [Interfaces] [C] Pointers -- B.3.2 Strings -- B.3.1 [System] Address_To_Access_Conversions -- 13.7.2 Machine_Code -- 13.8 Multiprocessors -- D.16 Dispatching_Domains -- D.16.1 RPC -- E.5 Storage_Pools -- 13.11 Subpools -- 13.11.4 !discussion The rules given in RM A(3/5-3.1/4) ensure that any globals referenced by language-defined packages are synchronized, except in the special case of the files identified by Current_Input and Current_Output. For these, as proposed above, we will specify the side effects using an appropriate Global aspect. Also, for cases where a parameter mode of IN is used for an operand that clearly is associated with updatable state, a Global aspect of the form OVERRIDING IN OUT Param will be used to capture the fact that some potentially non-synchronized state is being updated that is designated by the given Param. See the !proposal for more discussion and rationale. !ASIS No ASIS effect. !ACATS Test Unclear whether detailed testing is worthwhile, but some C-Tests that show that language-defined packages work in parallel operations when the default conflict checking policy is in effect would be valuable. !appendix From: Tucker Taft Sent: Tuesday, January 08, 2019 10:16 PM Here is a first attempt to indicate how we will specify the Global aspect of language-defined units. [This is version /01 of the AI - Editor.] No wording yet. **************************************************************** Summary of private mail between Tucker Taft, Randy Brukardt, and Steve Baird: Steve: I was only objecting to the statement in the !problem section This is not consistent with the requirement of RM A(3/5) that language-defined (generic) packages be reentrant. I don't see the inconsistency. I'm all in favor of this AI - I think there are very good arguments for it - but I don't buy the argument given in the !problem section. Specifically: A(3/5) is talking about a dynamic property: ... concurrent calls on any two (possibly the same) language-defined subprograms perform as specified, so long as ... I view this as a 100% dynamic semantics rule that is unaffected by what is specified for the Globals aspect of the subprograms in question; that (IMO) makes it tough to use this rule as justification for this AI. I certainly agree with the goal of this AI: we want to specify Globals aspects as precisely as possible in order to avoid disallowing things that don't need to be disallowed (and, perhaps for some compilers or tools, flagging thing that don't need to be flagged). Randy: > I suspect I might have forgotten about certain cases where we need > to include "& 'Global". I would guess that would be all of them. ;-) I've been assuming that generic units include all of their formal parameters in the Global for the package; individual operations could be more specific, but that's just too much work. The exception would be formal scalar types (which by definition cannot be blocking or use any globals). This AI needs to check all of the formals, because the editor doesn't want to do it alone. Randy: AI12-0112-1 handles all of the containers, including individual operations in many cases, so this AI doesn't need to mention them (other than that info). **************************************************************** From: Tucker Taft Sent: Tuesday, October 1, 2019 3:31 PM Here is an update to the AI defining the Global aspect for language-defined units. It incorporates the new "overriding" notion of the latest AI12-0240-6, and tries to address the issue of generic units more completely. [This is version /03 of the AI - Editor.] **************************************************************** From: Randy Brukardt Sent: Tuesday, October 1, 2019 7:03 PM You're still missing the note that AI12-0112-1 handles all of the container's Globals, including more specific ones when possible. You wouldn't want to list out all of the possibilities I came up with! - there's "null" (for pure navigation functions), the default of the package, "access ", some with specific formal parameters, and some combinations. The fact that this is not handled in this AI needs to be mentioned in this AI. ****************************************************************