Version 1.1 of acs/ac-00323.txt

Unformatted version of acs/ac-00323.txt version 1.1
Other versions for file acs/ac-00323.txt

!standard 6.1.2(0)          20-01-29 AC95-00323/00
!class Amendment 20-01-29
!status received no action 20-01-20
!status received 19-10-01
!subject Intro/Rationale for the Global aspect and Compound objects
!summary
[Editor's note: This is educational material rather than a language change itself. We put it here to preserve the discussion.]
!appendix

From: Tucker Taft
Sent: Tuesday, October 1, 2019  4:30 PM

I was tasked with writing an overview in the form of an introduction and
rationale for the Global aspect as proposed in AI12-0079 and augmented with the
Compound and Internal aspects of AI12-0240-6.  Here is that Intro/Rationale.

---------
Global aspect and Compound objects

AI12-0079-1 introduces the idea of a "Global" aspect to capture information
about the side-effects on global variables of calling a subprogram.  AI12-0240-6
introduces the notion of a "Compound" object as a way to simplify what needs to
be said in the Global aspect about the use of access types.  This note will try
to provide some introduction and rationale for these concepts.

Rationale for providing a Global aspect

The Pre and Post aspects are great in indicating what needs to be true before a
subprogram is called, and what is guaranteed to be true afterwards.
Unfortunately, a Post aspect is woefully incomplete in terms of capturing what
might happen to the overall state of the program as a result of calling a
subprogram.  What we need is to somehow indicate that some part of the state is
*not* affected, i.e. preserved, by the call.  A Global aspect is designed to
effectively do that, by stating what *might* be affected.  Any global variable
*not* "covered" by the Global aspect is guaranteed to be unaffected by calling
the subprogram.

Unit-Wide Defaults for the Global aspect

For simplicity we have defined defaults that mean the programmer need only
specify a Global aspect when they care about limiting the scope of possible
effects.  So that typically means that only if you are writing a Post aspect,
would you bother also specifying a more precise Global aspect.  We have also
provided an easy way to say that the only global variables affected are
"synchronized," meaning they are a protected object, a task object, an atomic
object, or some other language-defined object designed for use by multiple
threads of control, like a suspension object.  As another convenience, we allow
a default to be set at the package level, such as "Global => synchronized in out
all" which indicates that by default, it may be presumed that any global
variables updated by any subprogram in the package is a synchronized object.
The language-defined default for a package is "Global => null" for declared-pure
packages, and "Global => in out all" otherwise, which ensures that e sting Ada
2012 code need not be altered -- the language-provided defaults allow for any
existing legal use of globals.

As a simple example of a typical routine with a global side effect, a package
that provides a "stack" abstraction (without a stack "type") would typically
have Push, Pop, and Is_Empty operations.  Presuming the actual stack object is
declared somewhere in the package body, we might have:

   package Stack is
       procedure Push (X : Item_Type)
          with Global => in out Stack;

       function Pop return Item_Type
           with Global => in out Stack,
                Pre => not Is_Empty;

       function Is_Empty return Boolean
           with Global => in Stack;

       function Top return Item_Type
          with Global => in Stack
              Pre => not Is_Empty;
   end Stack;

Note that Pop uses mode "in out" since it has the effect of reducing the number
of items on the stack, while Top can use mode "in" since it returns the top item
on the stack without removing it.

Access types and the Global aspect

This all works pretty well until you start worrying about access types.  The
typical "model" for an access value is as an index into an associated access
"collection" associated with the access type.  And the model for an access
collection is essentially a global array, located where the access type is
declared.  This works pretty well for a pool-specific access type, but for
"general" access types, essentially all aliased objects of the designated type
become possible targets of a general access value, so that is a potentially very
large "collection" of objects.  Furthermore, in many cases the access type
itself is declared in the private part or package body, making it useless as a
way to define the external global effects.

Compound objects and Internal access values

In fact, many access values are used to connect the various pieces of a
"compound" object, such as a tree, or a linked list, or a hash table.  To avoid
having to worry about these "internal" access values when trying to describe the
global side effects of a subprogram, AI12-0240-6 has introduced the notion of a
"Compound" object and the associated "Internal" access values which link
together the pieces of the (conceptual) compound object, with the effect that
all of the pieces of a compound object can be treated, from the point of view of
Global aspects or subprogram parameters, as though they are "part" of the
overall compound object.

As an example, if we declare a particular kind of Hash_Table as being a
"Compound" type, and certain access values used in its representation as
"Internal," then we can effectively ignore the dereferencing of these internal
access values, and treat the target of the internal access value as if it is
just another pat of the same Hash_Table object.  The net effect is that we
effectively "suppress" Global aspect concerns when following internal access
values, and presume we are just poking around in the same overall object, just
as though we had done a simple component selection.  In other words, A.all.B is
treated like A.B if A is an internal access value.

Overriding parameter modes as part of the Global aspect

An additional issue with access types is that the parameter mode of a parameter
of an access type might not capture whether or not some piece of a compound
object rooted at the parameter is in fact updated by a call on the subprogram.
For Global aspects, we can insist that "out" or "in out" mode be used if the
global variable is in fact a "compound" object and some piece accessible via an
internal access value is going to be updated.  But for parameters, the parameter
modes are already defined to refer to whether or not the individual object
denoted by the actual parameter is going to be updated, and does not take into
account any possible effects on pieces reached indirectly via internal access
values.

To deal with this problem with existing parameter modes, we allow the Global
aspect to be used to "override" the parameter mode of a formal parameter, to
properly reflect whether some piece of the compound object rooted at the actual
parameter is going to be updated.  We use the "overriding" reserved word to
indicate this, also described in AI12-0240-6.   Perhaps the most well-known
example is Text_IO, where the File_Type parameter is "in" unless actually
opening, resetting, or closing the file, even though many operations have
side-effects on properties of the File_Type such as the Line, Col, or file
contents.  For such subprograms, we allow the user to override the parameter
mode specification as follows:

    procedure Put (File : in File_Type; Item : String)
       with Global => overriding in out File;

This indicates that File is actually a compound object, and some piece of the
information associated with the File is potentially being updated by the Put
operation.  We could be more specific about that by providing a Post aspect that
indicates how the Line or Col is being affected, for example.

Global aspect and relation to Access Parameters and Access Results

As a final issue, Ada allows passing parameters and returning results of an
anonymous access type.  In many ways, these "access parameters" and "access
results" might better be thought of a special kind of parameter/result "mode,"
rather than as being parameters/results of an access type.  Often the actual
access parameter is of the form "Obj'Access" (either explicitly, or implicitly
when in prefix notation), or the result of the function is immediately
dereferenced (e.g. Lookup(Map, Key).all := ...).  In general, the caller is
likely to "know" more about the designated object at the call site for an access
parameter, and similarly the function is likely to "know" more about the object
designated by the returned access value than the caller.

Given the above, as part of AI12-0240-6, we make the place with more knowledge
be the place where the Global aspect is enforced.  What this means is that at
the call site, a check is made that the access value being passed can be safely
dereferenced without violating the Global aspect, and similarly at a return
statement for a function with an access result, a check is made that the
function's Global aspect (or other parameter mode) allows the returned access
value to be dereferenced.  This ensures that the Global aspect is checked at the
place where the most knowledge resides, and allows Global aspects to be more
precise when desired.  The result of a function whose result type has the
Implicit_Deference aspect True is also checked at the point of the return
statement, for similar reasons.

As an example, imagine our Stack example, but now providing a Stack type, and
the use of access parameters and access results:

   package Stacks is
       type Stack is private;

       procedure Push (S : in out Stack; X : Item_Type);

       function Pop (S : access Stack) return Item_Type
           with Pre => not Is_Empty;

       function Is_Empty return Boolean
           with Global => in Stack;

       function Top (S : access constant Stack)
          return access constant Item_Type
             with Pre => not Is_Empty;
   private
        ...
   end Stack;

Clearly, the access parameter for Pop is essentially equivalent to using an
in-out mode, though the caller needs to write Stack_Obj'Access at the call site.
It would be cumbersome to define a Global aspect of function Pop to somehow
capture the fact that it is dereferencing the S parameter.   With AI12-0240-6,
we check the Global aspect at the point of call to be sure the caller has the
right to update the object denoted by the actual parameter, if it happens to be
a global variable.  Similarly, the result returned by Top is expressed as an
access result.  If in fact Top were returning a pointer to some arbitrary global
variable it would need to say that in its Global aspect.  But in fact since
there is no Global aspect, we can presume Top is returning a pointer to some
piece of the Stack object, so there is no need to have a Global aspect for Top,
and the caller can safely dereference the result returned by Top and know they
are not updating some Global variable, but instead dating a piece of something
that Top must have been given access to.

Conclusion

The net effect of the Global aspect and the Compound and Internal aspects is
that the programmer can capture the interesting side-effects of a subprogram in
a relatively economical fashion, without getting bogged down by the underlying
use of access values, access parameters, etc.  The package-level defaults mean
that many subprograms can share a common Global aspect, while only a few of the
subprograms need individual Global aspects.  The language defaults mean that
existing code need not specify any Global or Compound aspects, and will still be
compilable.

***************************************************************

From: Randy Brukardt
Sent: Tuesday, October 1, 2019  7:30 PM

> I was tasked with writing an overview in the form of an introduction
> and rationale for the Global aspect as proposed in AI12-0079 and
> augmented with the Compound and Internal aspects of AI12-0240-6.  Here
> is that Intro/Rationale.

As we discussed privately this morning, it might make sense to discuss the model
of Global for generic units, so that Global doesn't have to be "all" for a
generic unit even if all of the formals turn out to be "null".

Anything not mentioned in this overview seems like a candidate for
simplification. (Although necessarily the effect would be less specific, such as
replacing "access <some type>" with "all".)

***************************************************************

From: Tucker Taft
Sent: Tuesday, October 8, 2019 11:23 AM

[Here is a version with some typos/thinkos fixed.]

I was tasked with writing an overview in the form of an introduction and
rationale for the Global aspect as proposed in AI12-0079 and augmented with the
Compound and Internal aspects of AI12-0240-6.  Here is that Intro/Rationale.

---------
Global aspect and Compound objects

AI12-0079-1 introduces the idea of a "Global" aspect to capture information
about the side-effects on global variables of calling a subprogram.  AI12-0240-6
introduces the notion of a "Compound" object as a way to simplify what needs to
be said in the Global aspect about the use of access types.  This note will try
to provide some introduction and rationale for these concepts.

Rationale for providing a Global aspect

The Pre and Post aspects are great in indicating what needs to be true before a
subprogram is called, and what is guaranteed to be true afterwards.
Unfortunately, a Post aspect is woefully incomplete in terms of capturing what
might happen to the overall state of the program as a result of calling a
subprogram.  What we need is to somehow indicate that some part of the state is
*not* affected, i.e. preserved, by the call.  A Global aspect is designed to
effectively do that, by stating what *might* be affected.  Any global variable
*not* "covered" by the Global aspect is guaranteed to be unaffected by calling
the subprogram.

Unit-Wide Defaults for the Global aspect

For simplicity we have defined defaults that mean the programmer need only
specify a Global aspect when they care about limiting the scope of possible
effects.  So that typically means that only if you are writing a Post aspect,
would you bother also specifying a more precise Global aspect.  We have also
provided an easy way to say that the only global variables affected are
"synchronized," meaning they are a protected object, a task object, an atomic
object, or some other language-defined object designed for use by multiple
threads of control, like a suspension object.  As another convenience, we allow
a default to be set at the package level, such as "Global => synchronized in out
all" which indicates that by default, it may be presumed that any global
variables updated by any subprogram in the package is a synchronized object.
The language-defined default for a package is "Global => null" for declared-pure
packages, and "Global => in out all" otherwise, which ensures that e sting Ada
2012 code need not be altered -- the language-provided defaults allow for any
existing legal use of globals.

As a simple example of a typical routine with a global side effect, a package
that provides a "stack" abstraction (without a stack "type") would typically
have Push, Pop, and Is_Empty operations.  Presuming the actual stack object is
declared somewhere in the package body, we might have:

  package Stack is
      procedure Push (X : Item_Type)
         with Global => in out Stack;

      function Pop return Item_Type
          with Global => in out Stack,
               Pre => not Is_Empty;

      function Is_Empty return Boolean
          with Global => in Stack;

      function Top return Item_Type
         with Global => in Stack
             Pre => not Is_Empty;
  end Stack;

Note that Pop uses mode "in out" since it has the effect of reducing the number
of items on the stack, while Top can use mode "in" since it returns the top item
on the stack without removing it.

Access types and the Global aspect

This all works pretty well until you start worrying about access types.  The
typical "model" for an access value is as an index into an associated access
"collection" associated with the access type.  And the model for an access
collection is essentially a global array, located where the access type is
declared.  This works pretty well for a pool-specific access type, but for
"general" access types, essentially all aliased objects of the designated type
become possible targets of a general access value, so that is a potentially very
large "collection" of objects.  Furthermore, in many cases the access type
itself is declared in the private part or package body, making it useless as a
way to define the external global effects.

Compound objects and Internal access values

In fact, many access values are used to connect the various pieces of a
"compound" object, such as a tree, or a linked list, or a hash table.  To avoid
having to worry about these "internal" access values when trying to describe the
global side effects of a subprogram, AI12-0240-6 has introduced the notion of a
"Compound" object and the associated "Internal" access values which link
together the pieces of the (conceptual) compound object, with the effect that
all of the pieces of a compound object can be treated, from the point of view of
Global aspects or subprogram parameters, as though they are "part" of the
overall compound object.

As an example, if we declare a particular kind of Hash_Table as being a
"Compound" type, and certain access values used in its representation as
"Internal," then we can effectively ignore the dereferencing of these internal
access values, and treat the target of the internal access value as if it is
just another part of the same Hash_Table object.  The net effect is that we
effectively "suppress" Global aspect concerns when following internal access
values, and presume we are just poking around in the same overall object, just
as though we had done a simple component selection.  In other words, A.all.B is
treated like A.B if A is an internal access value.

Overriding parameter modes as part of the Global aspect

An additional issue with access types is that the parameter mode of a parameter
of an access (or private) type might not capture whether or not some piece of a
compound object rooted at the parameter is in fact updated by a call on the
subprogram.  For Global aspects, we can insist that "out" or "in out" mode be
used if the global variable is in fact a "compound" object and some piece
accessible via an internal access value is going to be updated.  But for
parameters, the parameter modes are already defined to refer to whether or not
the individual object denoted by the actual parameter is going to be updated,
and does not take into account any possible effects on pieces reached indirectly
via internal access values.

To deal with this problem with existing parameter modes, we allow the Global
aspect to be used to "override" the parameter mode of a formal parameter, to
properly reflect whether some piece of the compound object rooted at the actual
parameter is going to be updated.  We use the "overriding" reserved word to
indicate this, also described in AI12-0240-6.   Perhaps the most well-known
example is Text_IO, where the File_Type parameter is "in" unless actually
opening, resetting, or closing the file, even though many operations have
side-effects on properties of the File_Type such as the Line, Col, or file
contents.  For such subprograms, we allow the user to override the parameter
mode specification as follows:

   procedure Put (File : in File_Type; Item : String)
      with Global => overriding in out File;

This indicates that File is actually a compound object, and some piece of the
information associated with the File is potentially being updated by the Put
operation.  We could be more specific about that by providing a Post aspect that
indicates how the Line or Col is being affected, for example.

Global aspect and relation to Access Parameters and Access Results

As a final issue, Ada allows passing parameters and returning results of an
anonymous access type.  In many ways, these "access parameters" and "access
results" might better be thought of a special kind of parameter/result "mode,"
rather than as being parameters/results of an access type.  Often the actual
access parameter is of the form "Obj'Access" (either explicitly, or implicitly
when in prefix notation), or the result of the function is immediately
dereferenced (e.g. Lookup(Map, Key).all := ...).  In general, the caller is
likely to "know" more about the designated object at the call site for an access
parameter, and similarly the function is likely to "know" more about the object
designated by the returned access value than the caller.

Given the above, as part of AI12-0240-6, we make the place with more knowledge
be the place where the Global aspect is enforced.  What this means is that at
the call site, a check is made that the access value being passed can be safely
dereferenced without violating the Global aspect, and similarly at a return
statement for a function with an access result, a check is made that the
function's Global aspect (or other parameter mode) allows the returned access
value to be dereferenced.  This ensures that the Global aspect is checked at the
place where the most knowledge resides, and allows Global aspects to be more
precise when desired.  The result of a function whose result type has the
Implicit_Deference aspect True is also checked at the point of the return
statement, for similar reasons.

As an example, imagine our Stack example, but now providing a Stack type, and
the use of access parameters and access results:

  package Stacks is
      type Stack is private;

      procedure Push (S : access Stack; X : Item_Type);

      function Pop (S : access Stack) return Item_Type
          with Pre => not Is_Empty(S);

      function Is_Empty (S : access constant Stack) return Boolean;

      function Top (S : access constant Stack)
         return access constant Item_Type
            with Pre => not Is_Empty(S);
  private
       ...
  end Stacks;

Clearly, the access parameter for Pop is essentially equivalent to using an
in-out mode, though the caller needs to write Stack_Obj'Access at the call site.
It would be cumbersome to define a Global aspect of function Pop to somehow
capture the fact that it is dereferencing the S parameter.   With AI12-0240-6,
we check the Global aspect at the point of call to be sure the caller has the
right to update the object denoted by the actual parameter, if it happens to be
a global variable.  Similarly, the result returned by Top is expressed as an
access result.  If in fact Top were returning a pointer to some arbitrary global
variable it would need to say that in its Global aspect.  But in fact since
there is no Global aspect, we can presume Top is returning a pointer to some
piece of the Stack object, so there is no need to have a Global aspect for Top,
and the caller can safely dereference the result returned by Top and know they
are not referencing some Global variable, but inste referencing a piece of
something that Top must have been given access to.

Conclusion

The net effect of the Global aspect and the Compound and Internal aspects is
that the programmer can capture the interesting side-effects of a subprogram in
a relatively economical fashion, without getting bogged down by the underlying
use of access values, access parameters, etc.  The package-level defaults mean
that many subprograms can share a common Global aspect, while only a few of the
subprograms need individual Global aspects.  The language defaults mean that
existing code need not specify any Global or Compound aspects, and will still be
compilable.

***************************************************************

From: Tucker Taft
Sent: Tuesday, October 8, 2019  2:31 PM

I posted a version of this to a Google Drive, so you can read it and comment on it there:

   https://docs.google.com/document/d/1O8KhD9vL5FPO0XL2qyTA_WDglXaGWPoabMKUtIM-EpQ/edit?usp=sharing

***************************************************************

From: John Barnes
Sent: Monday, October 21, 2019  8:23 AM

I am at last getting around to looking at this global stuff and in particular
reviewing Tucks intro/rationale.

I will do this in two bites, sanitary bit ignoring access types. And then the
horrid access type stuff. I am doing this so that in the event of my getting fed
up and dying, at least, some comments on the first bit will have been done.  It
reads pretty well and my comments are trivial.

So hear are some comments down to the subheading "Access types and the Global
aspect".

In the para The Pre and Post aspects are great...

My first comment is that I am saddened by the drift in the use of great to mean
good whereas originally it basically meant just large as in "great with child".
Maybe say "they are wonderful for indicating what needs to be true.

I love the phrase "woefully incomplete".

In line 4, I I would insert "is" after i.e so it reads and change i.e to "that
is" to smooth the reading

...the state  "is not affected", that is, "is preserved" by the call

(As it reads now it could be misread (by an idiot perchance) to mean that
"affected" = "preserved".)

The para starting For simplicity...  third line might be better avoiding the
word "bother" thus

... would you need to specify a more precise Global aspect.

I would start a new para at !As another convenience...

And then    ..   if you say "any global variables" then maybe change "is a
synchronized object" to "are synchronized objects" or perhaps "constitute
synchronized objects". On the other hand maybe just make it "any global
variable".

In the example of the dear old well worn stack, the function Top needs a comma
after Stack to separate the two aspects.

Otherwise is crystal clear. And just the right level of detail.

End of comments.

***************************************************************

From: Tucker Taft
Sent: Monday, October 21, 2019  5:27 PM

Thanks, John!  I'll update the Google doc with your suggestions.

***************************************************************

From: Tucker Taft
Sent: Monday, October 21, 2019  5:27 PM

The Google Doc now incorporates John's comments.  I also did some minor formatting improvements:
  https://docs.google.com/document/d/1O8KhD9vL5FPO0XL2qyTA_WDglXaGWPoabMKUtIM-EpQ/

***************************************************************

From: John Barnes
Sent: Wednesday, October 23, 2019  4:30 PM

And here are some comments on the access type stuff. I found this very hard. It
makes me realise how rusty I have got.

In  this case I think it better for me to just embed some comments in the text.
Here goes.


Access types and the Global aspect

This all works pretty well until you start worrying about access types.  The
typical "model" for an access value is as an index into an associated access
"collection" associated with the access type.  And the model for an access
collection is essentially a global array, located where the access type is
declared.  This works pretty well for a pool-specific access type, but for
"general" access types, essentially all aliased objects of the designated type
become possible targets of a general access value, so that is a potentially very
large "collection" of objects.  Furthermore, in many cases the access type
itself is declared in the private part or package body, making it useless as a
way to define the external global effects.

*** "located where the access type is declared" makes me worry about those
anonymous access types that I have worried about ever since 2005. (I just reread
that part of the rationale for 2005. Did I write that?)

So where are they declared?***

Compound objects and Internal access values

In fact, many access values are used to connect the various pieces of a
"compound" object, such as a tree, or a linked list, or a hash table.  To avoid
having to worry about these "internal" access values when trying to describe the
global side effects of a subprogram, AI12-0240-6 has introduced the notion of a
"Compound" object and the associated "Internal" access values which link
together the pieces of the (conceptual) compound object, with the effect that
all of the pieces of a compound object can be treated, from the point of view of
Global aspects or subprogram parameters, as though they are "part" of the
overall compound object.

*** One frustration here is that we are talking about AI-240 that introduces
compound and initial. The intent is very clear - it's just another form of
abstraction hiding irrelevant detail. But there are no examples of the use of
these in this overview. I think they ought to be squeezed in somewhere. It's not
clear whether they are just concepts or actual aspects. ***

As an example, if we declare a particular kind of Hash_Table as being a
"Compound" type, and certain access values used in its representation as
"Internal," then we can effectively ignore the dereferencing of these internal
access values, and treat the target of the internal access value as if it is
just another part of the same Hash_Table object.  The net effect is that we
effectively "suppress" Global aspect concerns when following internal access
values, and presume we are just poking around in the same overall object, just
as though we had done a simple component selection.  In other words, A.all.B is
treated like A.B if A is an internal access value.

*** need a bit of example text here . This para starts "As an example" but its
all in the mind and not hard stuff that the humble programmer can glare at! ***

Overriding parameter modes as part of the Global aspect

An additional issue with access types is that the parameter mode of a parameter
of an access (or private) type might not capture whether or not some piece of a
compound object rooted at the parameter is in fact updated by a call on the
subprogram.  For Global aspects, we can insist that "out" or "in out" mode be
used if the global variable is in fact a "compound" object and some piece
accessible via an internal access value is going to be updated.  But for
parameters, the parameter modes are already defined to refer to whether or not
the individual object denoted by the actual parameter is going to be updated,
and does not take into account any possible effects on pieces reached indirectly
via internal access values.

*** The second sentence is referring to objects that are not parameters. It
should say so. ***

To deal with this problem with existing parameter modes, we allow the Global
aspect to be used to "override" the parameter mode of a formal parameter, to
properly reflect whether some piece of the compound object rooted at the actual
parameter is going to be updated.  We use the "overriding" reserved word to
indicate this, also described in AI12-0240-6.   Perhaps the most well-known
example is Text_IO, where the File_Type parameter is "in" unless actually
opening, resetting, or closing the file, even though many operations have
side-effects on properties of the File_Type such as the Line, Col, or file
contents.  For such subprograms, we allow the user to override the parameter
mode specification as follows:

  procedure Put (File : in File_Type; Item : String)
     with Global => overriding in out File;

*** I spent some time looking at the rationale for Ada 83 to see of there is a
mention of the reason for mode of the File being in but I guess its lost in the
mists of time.  It's pretty obvious that Put changes the actual file!! ***

This indicates that File is actually a compound object, and some piece of the
information associated with the File is potentially being updated by the Put
operation.  We could be more specific about that by providing a Post aspect that
indicates how the Line or Col is being affected, for example.

*** I would avoid ending that sentence with "for example" - it made me expect
one. t would be better to say  "We could, for example, be more specific … how
the Line or Col is being affected" ***

Global aspect and relation to Access Parameters and Access Results

As a final issue, Ada allows passing parameters and returning results of an
anonymous access type.  In many ways, these "access parameters" and "access
results" might better be thought of a special kind of parameter/result "mode,"
rather than as being parameters/results of an access type.  Often the actual
access parameter is of the form "Obj'Access" (either explicitly, or implicitly
when in prefix notation), or the result of the function is immediately
dereferenced (e.g. Lookup(Map, Key).all := ...).  In general, the caller is
likely to "know" more about the designated object at the call site for an access
parameter, and similarly the function is likely to "know" more about the object
designated by the returned access value than the caller.

Given the above, as part of AI12-0240-6, we make the place with more knowledge
be the place where the Global aspect is enforced.  What this means is that at
the call site, a check is made that the access value being passed can be safely
dereferenced without violating the Global aspect, and similarly at a return
statement for a function with an access result, a check is made that the
function's Global aspect (or other parameter mode) allows the returned access
value to be dereferenced.  This ensures that the Global aspect is checked at the
place where the most knowledge resides, and allows Global aspects to be more
precise when desired.  The result of a function whose result type has the
Implicit_Deference aspect True is also checked at the point of the return
statement, for similar reasons.

As an example, imagine our Stack example, but now providing a Stack type, and
the use of access parameters and access results:

 package Stacks is
     type Stack is private;

     procedure Push (S : access Stack; X : Item_Type);

     function Pop (S : access Stack) return Item_Type
         with Pre => not Is_Empty(S);

     function Is_Empty (S : access constant Stack) return Boolean;

     function Top (S : access constant Stack)
        return access constant Item_Type
           with Pre => not Is_Empty(S);
 private
      ...
 end Stacks;

*** The trouble with this example,. is that there is no actual new stuff to look
at! as is explained below. ***

Clearly, the access parameter for Pop is essentially equivalent to using an
in-out mode, though the caller needs to write Stack_Obj'Access at the call site.
It would be cumbersome to define a Global aspect of function Pop to somehow
capture the fact that it is dereferencing the S parameter.   With AI12-0240-6,
we check the Global aspect at the point of call to be sure the caller has the
right to update the object denoted by the actual parameter, if it happens to be
a global variable.  Similarly, the result returned by Top is expressed as an
access result.  If in fact Top were returning a pointer to some arbitrary global
variable it would need to say that in its Global aspect.  But in fact since
there is no Global aspect, we can presume Top is returning a pointer to some
piece of the Stack object, so there is no need to have a Global aspect for Top,
and the caller can safely dereference the result returned by Top and know they
are not referencing some Global variable, but inste referencing a piece of
something that Top must have been given access to.

*** Interesting that it turns out not to need anything. It would be nice to
contrast it with a fragment that does need some additional text.  ***

Conclusion

The net effect of the Global aspect and the Compound and Internal aspects is
that the programmer can capture the interesting side-effects of a subprogram in
a relatively economical fashion, without getting bogged down by the underlying
use of access values, access parameters, etc.  The package-level defaults mean
that many subprograms can share a common Global aspect, while only a few of the
subprograms need individual Global aspects.  The language defaults mean that
existing code need not specify any Global or Compound aspects, and will still be
compilable.

*** Last sentence is very important. Maybe it should be stated as a key goal
earlier on. ***

***************************************************************

From: Tucker Taft
Sent: Wednesday, October 23, 2019  12:56 PM

>And here are some comments on the access type stuff. I found this very hard.
>It makes me realise how rusty I have got.

>In  this case I think it better for me to just embed some comments in the
>text. Here goes.

>
>Access types and the Global aspect
>
>This all works pretty well until you start worrying about access types.
>The typical "model" for an access value is as an index into an associated
>access "collection" associated with the access type.  And the model for an
>access collection is essentially a global array, located where the access
>type is declared.  This works pretty well for a pool-specific access type,
>but for "general" access types, essentially all aliased objects of the
>designated type become possible targets of a general access value, so that
>is a potentially very large "collection" of objects.  Furthermore, in many
>cases the access type itself is declared in the private part or package
>body, making it useless as a way to define the external global effects.

>*** "located where the access type is declared" makes me worry about those
>anonymous access types that I have worried about ever since 2005. (I just
>reread that part of the rationale for 2005. Did I write that?)
>So where are they declared?***

Anonymous access types are always "general" access types, so it really
doesn't matter where they are declared.  They can designate objects from
pretty much any storage pool.  Since you can't directly apply an instance of
Unchecked_Deallocation to an object of an anonymous access type, the actual
storage pool is normally not very relevant.  But as far as this "model" goes,
an object of an anonymous access type can designate any aliased object of the
appropriate type (or types, if it is access T'Class).

>Compound objects and Internal access values
>
>In fact, many access values are used to connect the various pieces of a
>"compound" object, such as a tree, or a linked list, or a hash table.  To
>avoid having to worry about these "internal" access values when trying to
>describe the global side effects of a subprogram, AI12-0240-6 has introduced
>the notion of a "Compound" object and the associated "Internal" access values
>which link together the pieces of the (conceptual) compound object, with the
>effect that all of the pieces of a compound object can be treated, from the
>point of view of Global aspects or subprogram parameters, as though they are
>"part" of the overall compound object.

>*** One frustration here is that we are talking about AI-240 that introduces
>compound and initial. The intent is very clear - it's just another form of
>abstraction hiding irrelevant detail. But there are no examples of the use
>of these in this overview. I think they ought to be squeezed in somewhere.
>It's not clear whether they are just concepts or actual aspects. ***

But in the next paragraph I provide an example of a hash table, which I
presumed the reader was familiar with enough to know that access types are
used in multiple places in a typical hash table.  I didn't want to get
bogged down in the details of a particular hash-table implementation.


>As an example, if we declare a particular kind of Hash_Table as being a
>"Compound" type, and certain access values used in its representation as
>"Internal," then we can effectively ignore the dereferencing of these
>internal access values, and treat the target of the internal access value
>as if it is just another part of the same Hash_Table object.  The net
>effect is that we effectively "suppress" Global aspect concerns when
>following internal access values, and presume we are just poking around
>in the same overall object, just as though we had done a simple component
> selection.  In other words, A.all.B is treated like A.B if A is an
>internal access value.

>*** need a bit of example text here . This para starts "As an example" but
>its all in the mind and not hard stuff that the humble programmer can
>glare at! ***

OK, so you want some Ada code, not just hand waving...

>Overriding parameter modes as part of the Global aspect
>
>An additional issue with access types is that the parameter mode of a
>parameter of an access (or private) type might not capture whether or not
>some piece of a compound object rooted at the parameter is in fact updated
>by a call on the subprogram.  For Global aspects, we can insist that "out"
>or "in out" mode be used if the global variable is in fact a "compound"
>object and some piece accessible via an internal access value is going to
>be updated.  But for parameters, the parameter modes are already defined
>to refer to whether or not the individual object denoted by the actual
>parameter is going to be updated, and does not take into account any
>possible effects on pieces reached indirectly via internal access values.

>*** The second sentence is referring to objects that are not parameters. It
>should say so. ***

I sort of thought it did, but I'll try to clarify further.

...
>This indicates that File is actually a compound object, and some piece of
>the information associated with the File is potentially being updated by the
>Put operation.  We could be more specific about that by providing a Post aspect
>that indicates how the Line or Col is being affected, for example.

>*** I would avoid ending that sentence with "for example" - it made me expect
>one. t would be better to say  "We could, for example, be more specific ...
>how the Line or Col is being affected" ***

Got it.

>Global aspect and relation to Access Parameters and Access Results

...
>Clearly, the access parameter for Pop is essentially equivalent to using an
>in-out mode, though the caller needs to write Stack_Obj'Access at the call site.
>It would be cumbersome to define a Global aspect of function Pop to somehow
>capture the fact that it is dereferencing the S parameter.   With AI12-0240-6,
>we check the Global aspect at the point of call to be sure the caller has the
>right to update the object denoted by the actual parameter, if it happens to be
>a global variable.  Similarly, the result returned by Top is expressed as an
>access result.  If in fact Top were returning a pointer to some arbitrary global
>variable it would need to say that in its Global aspect.  But in fact since
>there is no Global aspect, we can presume Top is returning a pointer to some
>piece of the Stack object, so there is no need to have a Global aspect for Top,
>and the caller can safely dereference the result returned by Top and know they
>are not referencing some Global variable, but inste referencing a piece of
>something that Top must have been given access to.

>*** Interesting that it turns out not to need anything. It would be nice to
>contrast it with a fragment that does need some additional text.  ***

OK, I'll try to illustrate that.

>Conclusion
>
>The net effect of the Global aspect and the Compound and Internal aspects is
>that the programmer can capture the interesting side-effects of a subprogram in
>a relatively economical fashion, without getting bogged down by the underlying
>use of access values, access parameters, etc.  The package-level defaults mean
>that many subprograms can share a common Global aspect, while only a few of the
>subprograms need individual Global aspects.  The language defaults mean that
>existing code need not specify any Global or Compound aspects, and will still be
>compilable.

>*** Last sentence is very important. Maybe it should be stated as a key goal
>earlier on. ***

It is mentioned, but I'll add a specific goal in an early paragraph.

Thanks for the careful review.

Here is an updated version with an attempt to address your latest comments:
  https://docs.google.com/document/d/1O8KhD9vL5FPO0XL2qyTA_WDglXaGWPoabMKUtIM-EpQ/

***************************************************************

From: Jeff Cousins
Sent: Wednesday, October 23, 2019  4:40 AM

Unit-Wide Defaults for the Global aspect

I find using just the word "Global" for name of the package level aspect a bit
misleading.  It implies that it is relative to the package, whereas it is
setting the default for the subprograms within the package.  Setting "Global =>
[] in out all" on the package implies that variables external to the package are
accessed, whereas the variables accessed, although external to the subprograms,
may be within the package - as is the case for the stack object in the example
that follows.

Maybe it could be called "Default_Global"?

***************************************************************

From: Tucker Taft
Sent: Wednesday, October 23, 2019  6:49 AM

Thanks, Jeff.  There have been others with a similar comment in the past (e.g.
Florian).  One concern is that in some cases it is providing both a definition
of the Global effects for the program unit itself, and a default for nested
units.  This might not be true for packages, but it is true for almost any other
kind of program unit, so it seems a bit odd for packages to require the use of
"Default_Global" whereas for all other program units, "Global" by itself covers
both meanings.  Perhaps Global could imply Default_Global in the absence of a
separate specification for Default_Global.  Or vice versa? ;-)

***************************************************************

From: Jeff Cousins
Sent: Wednesday, October 23, 2019  1:27 PM

What are you thinking of by "the Global effects for the program unit itself"?
If the library unit is a stand-alone subprogram, presumably that's the most
straightforward case.

Or you thinking of the effects of the package elaboration code?  In which case
I’d have both a Global aspect for the effects of the package elaboration code
and a Default_Global aspect for setting the default global for the subprograms
within the package.

Re nested subprograms, presumably the Global for the containing subprogram has
to include the possible effects of any nested subprograms, as (if called at all)
they can only be called from within the containing subprogram.  So it would seem
perfectly reasonable to me for a nested subprogram to default to the global of
the containing subprogram.

***************************************************************

From: Tucker Taft
Sent: Wednesday, October 23, 2019  1:42 PM

>What are you thinking of by "the Global effects for the program unit itself"?
>If the library unit is a stand-alone subprogram, presumably that's the most
>straightforward case.

>Or you thinking of the effects of the package elaboration code?  In which case
>I'd have both a Global aspect for the effects of the package elaboration code
>and a Default_Global aspect for setting the default global for the subprograms
>within the package.

I am not convinced that having both actually provides sufficient benefit.  It
would seem that the effects of the package elaboration code would almost always
be a good default for the package as a whole, and vice-versa.

>Re nested subprograms, presumably the Global for the containing subprogram has
>to include the possible effects of any nested subprograms, as (if called at all)
>they can only be called from within the containing subprogram.  So it would seem
>perfectly reasonable to me for a nested subprogram to default to the global of
>the containing subprogram.

So in this case, you don't see the need for a separate aspect, I presume.  I
would think the same would apply for a task unit.

Given the above, having two aspects seems only justified if we think it is
likely for the Default_Global for a package to differ from the Global for the
elaboration code.  We certainly could have both, but I would think that if you
only specify one, then the other should default to be the same, rather than
falling back to some enclosing default.

***************************************************************

From: Richard Wai
Sent: Wednesday, October 23, 2019  2:48 PM

Just to add to this..

>I find using just the word "Global" for name of the package level aspect a bit
>misleading.  It implies that it is relative to the package, whereas it is
>setting the default for the subprograms within the package.  Setting "Global =>
>[] in out all" on the package implies that variables external to the package are
>accessed, whereas the variables accessed, although external to the subprograms,
>may be within the package - as is the case for the stack object in the example
>that follows. Maybe it could be called "Default_Global"?

My understanding of the global aspect on packages was that it does indeed apply
to scopes that form the context of the package, and is not just a default for
the contents of the package.

Ergo:

with Ada.Text_IO;

package My_Package with Global => null is

   procedure New_Line (Count: Positive) renames Ada.Text_IO.New_Line;  -- Illegal

end My_Package;

Referring to an entity that is "global" (withed, in this case) to the package
would not be allowed since Global => null

Another example is regular extension, i.e:

package Parent_Package.Child_Packge with Global => null is

         Child_Variable: Parent_Type := Parent_Variable; -- illegal

end package;

At the end of the day, I'd think that from a user perspective,  global acting
differently for packages or even library units will be unexpected.

***************************************************************

From: Richard Wai
Sent: Wednesday, October 23, 2019  3:08 PM

>Referring to an entity that is "global" (withed, in this case) to the package
>would not be allowed since Global => null

Sorry - this was silly of me. Global is for variables not just any name! So
never mind this part.

***************************************************************

From: Jeff Cousins
Sent: Friday, October 25, 2019  1:27 PM

>It would seem that the effects of the package elaboration code would almost
>always be a good default for the package as a whole, and vice-versa

Maybe, but have you any evidence for/examples of this?  I would have thought
>that package elaboration code was mostly initialising local variables, with
>no global effect.  I think the most likely scenario for package elaboration
>code accessing global data would be reading configuration data, e.g.
>Max_No_Of_XYZs_Fitted_To_My_Specific_Ship/Aircraft, and sizing local arrays
>and counts accordingly, but even that would only be in a minority of cases.

***************************************************************

From: Jean-Pierre Rosen
Sent: Friday, October 25, 2019  9:17 AM

Or take the example of a GUI package, where you initialize GTK, create windows
and menus, etc...

***************************************************************

From: Tucker Taft
Sent: Friday, October 25, 2019  2:07 PM

We clearly need to define more clearly what we mean by "global".  Relative to
the elaboration "procedure" all of the variables within the package are
"global."  That is, they continue to exist after the elaboration procedure
completes.  So "global" is not a visibility thing, but rather a lifetime thing.
Your interpretation of "global" as being "not local to the package" also makes
sense.

We are currently debating whether to continue to use the term "Global" for this
aspect because of possible compatibility issues with existing SPARK usage.  This
might be another argument in favor of shifting our terminology to avoid
confusion.

***************************************************************

From: Claire Dross
Sent: Wednesday, November 20, 2019  9:04 AM

> We are currently debating whether to continue to use the term "Global"
> for this aspect because of possible compatibility issues with existing
> SPARK usage.  This might be another argument in favor of shifting our
> terminology to avoid confusion.

Sorry for my late reply on this issue. I feel like having two different
aspects with two slightly different meanings, one for SPARK and one for
Ada would be harmful for the effort of bringing Ada and SPARK together
(all the more if these aspects are incompatible). I think we should strive
to get a Global aspect for Ada which is at least compatible with SPARK.

***************************************************************

From: John Barnes
Sent: Wednesday, October 30, 2019  2:59 AM

Why are you using this Google thing?  Its tricky to print.

Do you have shares in Google? Or is it to do with Pascal?

***************************************************************

From: Tucker Taft
Sent: Thursday, October 31, 2019  7:41 AM

I suggest you use the File menu, then click Download, and "Download as PDF."
It should be easy to print the PDF after downloading it.

***************************************************************

Here is the document as it was last updated in November 2019. - Editor


Global aspect and Compound objects

AI12-0079-1 introduces the idea of a "Global" aspect to capture information
about the side-effects on global variables of calling a subprogram.  AI12-0240-6
introduces the notion of a "Compound" object as a way to simplify what needs to
be said in the Global aspect about the use of access types.  This note will try
to provide some introduction and rationale for these concepts.

Rationale for providing a Global aspect

The Pre and Post aspects are wonderful for indicating what needs to be true
before a subprogram is called, and what is guaranteed to be true afterwards.
Unfortunately, a Post aspect is woefully incomplete in terms of capturing what
might happen to the overall state of the program as a result of calling a
subprogram.  What we need is to somehow indicate that some part of the state is
*not* affected by the call, that is, is preserved by the call.  A Global aspect
is designed to effectively do that, by stating what *might* be affected.  Any
global variable *not* "covered" by the Global aspect is guaranteed to be
unaffected by calling the subprogram.  However, we don’t want to require any
explicit Global aspects on existing code, so we need good defaults in the
absence of explicit Global aspects.

Unit-Wide Defaults for the Global aspect

For simplicity we have defined defaults that mean the programmer need only
specify a Global aspect when they care about limiting the scope of possible
effects.  So that typically means that only if you are writing a Post aspect,
would you need to specify a more precise Global aspect.  We have also provided
an easy way to say that the only global variables affected are "synchronized,"
meaning they are a protected object, a task object, an atomic object, or some
other language-defined object designed for use by multiple threads of control,
like a suspension object.

As another convenience, we allow a default to be set at the package level, such
as "Global => synchronized in out all" which indicates that by default, it may
be presumed that any global variable updated by any subprogram in the package is
a synchronized object.  The language-defined default for a package is "Global =>
null" for declared-pure packages, and "Global => in out all" otherwise, which
ensures that existing Ada 2012 code need not be altered -- the language-provided
defaults allow for any existing legal use of globals.

As a simple example of a typical routine with a global side effect, a package
that provides a "stack" abstraction (without a stack "type") would typically
have Push, Pop, and Is_Empty operations.  Presuming the actual stack object is
declared somewhere in the package body, we might have:

 package Stack is
     procedure Push (X : Item_Type)
        with Global => in out Stack;

     function Pop return Item_Type
         with Global => in out Stack,
              Pre => not Is_Empty;

     function Is_Empty return Boolean
         with Global => in Stack;

     function Top return Item_Type
        with Global => in Stack,
            Pre => not Is_Empty;
 end Stack;

Note that Pop uses mode "in out" since it has the effect of reducing the number
of items on the stack, while Top can use mode "in" since it returns the top item
on the stack without removing it.

Access types and the Global aspect

This all works pretty well until you start worrying about access types.  The
typical "model" for an access value is as an index into an associated access
"collection" associated with the access type.  And the model for an access
collection is essentially a global array, located where the access type is
declared.  This works pretty well for a pool-specific access type, but for
"general" access types, essentially all aliased objects of the designated type
become possible targets of a general access value, so that is a potentially very
large "collection" of objects.  Furthermore, in many cases the access type
itself is declared in the private part or package body, making it useless as a
way to define the external global effects.

Compound objects and Internal access values

In fact, many access values are used to connect the various pieces of a
"compound" object, such as a tree, or a linked list, or a hash table.  To avoid
having to worry about these "internal" access values when trying to describe the
global side effects of a subprogram, AI12-0240-6 has introduced the notion of a
"Compound" object and the associated "Internal" access values which link
together the pieces of the (conceptual) compound object, with the effect that
all of the pieces of a compound object can be treated, from the point of view of
Global aspects or subprogram parameters, as though they are "part" of the
overall compound object.

As an example, if we declare a particular kind of Hash_Table as being a
"Compound" type, and certain access values used in its representation as
"Internal," then we can effectively ignore the dereferencing of these internal
access values, and treat the target of the internal access value as if it is
just another part of the same Hash_Table object.  The net effect is that we
effectively "suppress" Global aspect concerns when following internal access
values, and presume we are just poking around in the same overall object, just
as though we had done a simple component selection.  In other words, A.all.B is
treated like A.B if A is an internal access value.

Here is an example of a simple Hash_Table.  All access types in this example are
Internal, and all composite objects are marked as Compound.  Given such a
Hash_Table, the Nodes in the Backbone are treated like direct subcomponents of
the Hash_Table, rather than as being separate objects in some access collection,
from the point of view of the Global aspect:

  type Node;
  type Node_List is access Node with Internal;
  type Node is record
     Val : Elem_Type;
     Next : Node_List;
  end record with Compound;
  type Node_List_Array is array (Natural range <>) of Node_List with Compound;
  type Hash_Table is record
     Num_Elements : Natural := 0;
     Backbone : access Node_List_Array with Internal;
  end record with Compound;

Overriding parameter modes as part of the Global aspect

An additional issue with access types is that the parameter mode of a parameter
of an access (or private) type might not capture whether or not some piece of a
compound object rooted at the parameter is in fact updated by a call on the
subprogram.  For specifying something about a global variable, we can insist
that "out" or "in out" mode be used in the Global aspect if the global variable
is in fact a "compound" object and some piece designated by an internal access
value is going to be updated.  But for parameters, the parameter modes are
already defined to refer to whether or not the individual object denoted by the
actual parameter is going to be updated, and does not take into account any
possible effects on pieces reached indirectly via internal access values.

To deal with this problem with existing parameter modes, we allow the Global
aspect to be used to "override" the parameter mode of a formal parameter, to
properly reflect whether some piece of the compound object rooted at the actual
parameter is going to be updated.  We use the "overriding" reserved word to
indicate this, also described in AI12-0240-6.   Perhaps the most well-known
example is Text_IO, where the File_Type parameter is "in" unless actually
opening, resetting, or closing the file, even though many operations have
side-effects on properties of the File_Type such as the Line, Col, or file
contents. For such subprograms, we allow the user to override the parameter mode
specification as follows:

  procedure Put (File : in File_Type; Item : String)
     with Global => overriding in out File;

This indicates that File is actually a compound object, and some piece of the
information associated with the File is potentially being updated by the Put
operation.  We could be more specific about that by providing, for example, a
Post aspect that indicates how the Line or Col is being affected. Global aspect
and relation to Access Parameters and Access Results As a final issue, Ada
allows passing parameters and returning results of an anonymous access type.  In
many ways, these "access parameters" and "access results" might better be
thought of a special kind of parameter/result "mode," rather than as being
parameters/results of an access type.  Often the actual access parameter is of
the form "Obj'Access" (either explicitly, or implicitly when in prefix
notation), or the result of the function is immediately dereferenced (e.g.
Lookup(Map, Key).all := ...).  In general, the caller is likely to "know" more
about the designated object at the call site for an access parameter, and
similarly the function is likely to "know" more about the object designated by
the returned access value than the caller.

Given the above, as part of AI12-0240-6, we make the place with more knowledge
be the place where the Global aspect is enforced.  What this means is that at
the call site, a check is made that the access value being passed can be safely
dereferenced without violating the Global aspect, and similarly at a return
statement for a function with an access result, a check is made that the
function's Global aspect (or other parameter mode) allows the returned access
value to be dereferenced.  This ensures that the Global aspect is checked at the
place where the most knowledge resides, and allows Global aspects to be more
precise when desired.  The result of a function whose result type has the
Implicit_Deference aspect True is also checked at the point of the return
statement, for similar reasons.

As an example, imagine our Stack example, but now providing a Stack type, and
the use of access parameters and access results:

 package Stacks is
     type Stack is private;

     procedure Push (S : access Stack; X : Item_Type);

     function Pop (S : access Stack) return Item_Type
         with Pre => not Is_Empty(S);

     function Is_Empty (S : access constant Stack) return Boolean;

     function Top (S : access constant Stack)
        return access constant Item_Type
           with Pre => not Is_Empty(S);
 private
      ...
 end Stacks;

Clearly, the access parameter for Pop is essentially equivalent to using an
in-out mode, though the caller needs to write Stack_Obj'Access at the call site.
It would be cumbersome to define a Global aspect of function Pop to somehow
capture the fact that it is dereferencing the S parameter.   With AI12-0240-6,
we check the Global aspect at the point of call to be sure the caller has the
right to update the object denoted by the actual parameter, if it happens to be
a global variable.  Similarly, the result returned by Top is expressed as an
access result.  If in fact Top were returning a pointer to some arbitrary global
variable it would need to say that in its Global aspect.  But in fact since
there is no Global aspect, we can presume Top is returning a pointer to some
piece of the Stack object, so there is no need to have a Global aspect for Top,
and the caller can safely dereference the result returned by Top and know they
are not referencing some Global variable, but instea referencing a piece of
something that Top must have been given access to.

Note that if we went back to our original Stack abstraction, where there is a
single global stack object within the package, and defined a Writable_Top
function that returned "access Item_Type":

  function Writable_Top return access Item_Type
     with Pre => not Is_Empty,
          Global => in out Stack;

we would have to use "in out" mode to indicate we are effectively updating the
state of the Global Stack abstraction, even though the actual update wouldn’t
happen, presumably, until after the function returns.

This notion of embedding the Global aspect check at the point where the access
value is passed or returned, rather than where it is dereferenced, is quite
consistent with the way the rules about "access" vs. "access constant" work, or
"in" vs. "in out" for a by-reference parameter.  In both cases, there is no
immediate "update" happening on the object designated or denoted by the object
being passed or returned, but rather there is a check that it is "OK" to perform
that update at some later point.

Conclusion

The net effect of the Global aspect and the Compound and Internal aspects is
that the programmer can capture the interesting side-effects of a subprogram in
a relatively economical fashion, without getting bogged down by the underlying
use of access values, access parameters, etc.  The package-level defaults mean
that many subprograms can share a common Global aspect, while only a few of the
subprograms need individual Global aspects.  The language defaults mean that
existing code need not specify any Global or Compound aspects, and will still be
compilable.

***************************************************************

Questions? Ask the ACAA Technical Agent