Version 1.3 of ai12s/ai12-0302-1.txt
!standard A(15) 19-05-31 AI12-0302-1/02
!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 packages (generic or not) will have Global => synchronized
in out <unit>. Subprograms that refer to the internal state of an
object identified by some sort of handle passed as a parameter (e.g.
File_Type and Generator), will have Global => in [out] <param>.all.
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 others, we will insert an explicit:
Global => synchronized in out <unit_name>
where <unit_name> is the name of the package or generic package for
which the Global aspect is specified. For library (generic) subprograms
that are not merely renames of some subprogram declared elsewhere, the
<unit_name> will refer to the parent package (or generic package) of the
library (generic) subprogram.
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 <unit_name>" is appropriate for each. 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 either:
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, 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 a global_name to be of the form X.all, where X
statically denotes an object, including possibly a formal parameter.
Hence, Put, Get, and Col become:
procedure Put (File : File_Type; Item : String)
with Global => in out File.all;
procedure Get (File : File_Type; Item : out String)
with Global => in out File.all;
function Col (File : File_Type) return Positive_Count
with Global => in File.all;
Note that we need to mention File.all in the Global aspect for Col, because
it is reading state updated by Put and Get. When the File is itself of
"in out" mode, we don't need any Global aspect, because clearly changing
File as a whole can cause us to refer to completely new file position
information. The model is that data that is affected by Open/Close,
such as the associated Name, will logically reside "directly" within
the File_Type object. For data that is affected by Read/Write, such
as Col and Line, it will reside in an object that is designated by
some part of the File_Type object, allowing the use of an IN parameter.
Using the same approach, Random becomes:
function Random(Gen : Generator) return Result_Subtype
with Global => in out Gen.all;
To be consistent, presuming the actual "seed" resides at Gen.all, we also
need to add Global references to Gen.all for all of the various Reset
procedures (in out Gen.all), the Save procedure (in Gen.all), and the
Image function (in Gen.all).
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 <unit_name>"
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] <unit_name>" when they refer to implicit state that is
not synchronized, and "in [out] <param>.all" when they refer to the
variable state associated with a dereference of an IN parameter.
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 => in out Subpool.all;
Modify Pool_Of_Subpool to have:
with Global => in Subpool.all;
---
Within A.5.2, Discrete_Random and Float_Random:
Modify Random, Reset to have
with Global => in out Gen.all;
Modify Save, Image to have
with Global => in Gen.all;
---
Within A.8.1, Sequential_IO:
Modify Flush, Read, Write to have
with Global => in out File.all;
Modify End_Of_File to have
with Global => in File.all;
---
Within A.8.4, Direct_IO:
Modify Flush, Read, Write, Set_Index to have:
with Global => in out File.all;
Modify Index, Size, End_Of_File to have:
with Global => in File.all;
---
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 => in out File.all;
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;
Modify File_Type versions of:
Line_Length, Page_Length, End_Of_Line, End_Of_Page,
End_Of_File, Col, Line, Page
to have
with Global => in File.all;
---
Within A.12.1, Stream_IO:
Modify Read, Write, Set_Index to have:
with Global => in out File.all;
Modify End_Of_File, Index, Size to have:
with Global => in File.all;
---
---------------
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 Param.all 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 "& <formal_type>'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).
****************************************************************
Questions? Ask the ACAA Technical Agent