Version 1.1 of ai12s/ai12-0302-1.txt
!standard A etc. 19-01-10 AI12-0302-1/01
!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>.
!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 return a File_Type, which
is limited private, rather than a visible access type.
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 in the associated package, as we did above for Current_Input
and Current_Output. Alternatively, we could generalize the Global aspect
to allow us to specify the name of an IN parameter with mode "in out" to
indicate that the state "owned" by the IN parameter is in fact updated
by the call. Hence:
function Random(Gen : Generator) return Result_Subtype
with Global => in out Gen;
However that is a bit of a perversion of the notion of a
Global aspect, and provides additional justification for introducing a
separate aspect for identifying things that are modified by a call, that
might not necessarily be considered "global." Hence, we could introduce
a new "Modifies" aspect which is specifically designed to allow one
to specify more precisely what is possibly modified by a call, including
a particular part of a visibly composite parameter. Hence:
function Random(Gen : Generator) return Result_Subtype
with Modifies => Gen;
This would be used to more precisely indicate what is being modified, and
also allow the ability to say that state associated with an IN parameter
is modified. We will have to decide whether it is worth defining this
additional Modifies aspect for this purpose. The alternative, as
mentioned, is to presume the state is part of some collection within
the enclosing (generic) package (e.g. Discrete_Random) and fall back on:
function Random(Gen : Generator) return Result_Subtype
with Global => in out Discrete_Random;
This overstates the effects of Random, effectively considering
concurrent uses of otherwise independent random number streams
as being conflicting.
Note that if we accept the notion that we treat a handle as "owning"
any data "associated" with the handle, we could identify Current_Input
or Current_Output in the Global aspect for a subprogram like
Put_Line:
procedure Put_Line (Item : String)
with Global => (in out Current_Output, synchronized in out Text_IO);
Here "Global" does seem appropriate, since there is no parameter that
is specifying the file being modified. It is a bit odd that you must
call a function (Current_Output in this case) to determine what global
object is being updated, but this makes sense in the context of a
handle that is considered to "own" the associated updatable state.
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 retured reference refers to some part of
Container. This is probably best handled with a postcondition using the
Overlaps_Storage attribute:
function Reference(Container : aliased in out Map; ...)
return Reference_Type;
with Post => Container'Overlaps_Storage(Reference'Result.Element.all);
presuming X'Overlaps_Storage(Y) in the presence of owner pointers means
Y overlaps with something "owned" (directly or indirectly) by X.
So to summarize the proposal, each library unit will have a default
specification of the Global aspect, to either "null" for pure library units,
or "synchronized in out <unit_name>" for impure library units. And then
within the impure units, individual subprograms will override this
default when they refer to implicit state (Current_Input or Current_Output)
or they have "in" parameters that are handles owning updatable state that
is not required by the language to be synchronized.
The relevant subprograms requiring special Global aspects (and/or Modifies
aspects, should we decide to have such an aspect):
* Put/Get/Set operations on Current_Output/Current_Input/Current_Error
* Put/Get/.. operations on File_Type parameters where the
File_Type is an IN parameter.
* Operations on Random Number generators where the generator
is an IN parameter
---------------
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
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
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
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_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]
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]
Stream_IO — A.12.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_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
[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 or a Modifies aspect (should we decide to support
that) will be used to capture the fact that some potentially non-synchronized
state is being updated.
!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.
****************************************************************
Questions? Ask the ACAA Technical Agent