Version 1.7 of ais/ai-00225.txt

Unformatted version of ais/ai-00225.txt version 1.7
Other versions for file ais/ai-00225.txt

!standard 3.10 (09)          02-06-07 AI95-00225/04
!class binding interpretation 99-12-09
!status Amendment 200Y 02-07-10
!status WG9 Approved 02-06-21
!status ARG Approved 8-0-0 01-10-07
!status work item 99-12-09
!status received 99-12-09
!qualifier Clarification
!priority Medium
!difficulty Medium
!subject Aliased current instance for limited types
!summary
The current instance of a type is aliased if and only if:
The type is tagged and limited; or The type has the reserved word limited in its full definition.
!question
The attributes Access and Unchecked_Access are allowed only on aliased objects, "including possibly the current instance of a limited type within its definition", in the words of the standard (3.10.2(24/1)).
But the standard never says where the type is limited. There are types that can become nonlimited later in their immediate scope, because the full type of a component turns out to be nonlimited. There are also cases where in a generic package a type looks limited, but from outside a particular instance, the type looks nonlimited, because the "formally" limited components were not "actually" limited.
Is it intended that the legality of Access and Unchecked_Access depends on the ultimate limitedness of the type? (No.) If not, what is the intent? (See summary.)
!recommendation
(See summary.)
!wording
(See summary.)
!discussion
The crux of the problem is that a type can become non-limited at some arbitrary later point in its scope. This makes implementing this rule problematical.
One solution is to make the check when an object is declared. While this works, it goes against the Ada 95 design principle of detecting errors as soon as possible.
Another possibility is to make the check at the freezing point of the type. While more information is known at this point, it still is possible for the type to become non-limited later (if a component type becomes non-limited, for instance). So this is not sufficient, some checking still has to be deferred.
The difficulty of making the check raises the question as to whether this complex check is helpful to Ada users. Since it is unclear if a type is limited, users may be confused as to whether 'Access is allowed. This is not helpful.
Therefore, we adopt the easily understood rule, either the type is limited tagged (in which case the limitedness can't change) or the type was explicitly declared with the reserved word limited (and again it cannot become non-limited). This will eliminate confusion and simplify the job of compilers.
This rule has the nice property that only types that are return-by-reference have an aliased current instance. That's good, because if they are not return-by-reference, (and not controlled), then the object is allowed to be copied and moved around as part of a function return, which would render the use of the Access attribute meaningless.
It is true that this new rule could break existing code. But existing compilers seem to make this check in different ways, which means that code is not portable. And any such code is rather pathological, as it could break if the type is returned from a function.
!ACATS test
A test should be constructed for these cases, or a new subtest added to one of the existing tests (B3A2015, B3A0004, B3A0001).
!corrigendum 3.10(09)
Replace the paragraph:
A view of an object is defined to be aliased if it is defined by an object_declaration or component_definition with the reserved word aliased, or by a renaming of an aliased view. In addition, the dereference of an access-to-object value denotes an aliased view, as does a view conversion (see 4.6) of an aliased view. Finally, the current instance of a limited type, and a formal parameter or generic formal object of a tagged type are defined to be aliased. Aliased views are the ones that can be designated by an access value. If the view defined by an object_declaration is aliased, and the type of the object has discriminants, then the object is constrained; if its nominal subtype is unconstrained, then the object is constrained by its initial value. Similarly, if the object created by an allocator has discriminants, the object is constrained, either by the designated subtype, or by its initial value.
by:
A view of an object is defined to be aliased if it is defined by an object_declaration or component_definition with the reserved word aliased, or by a renaming of an aliased view. In addition, the dereference of an access-to-object value denotes an aliased view, as does a view conversion (see 4.6) of an aliased view. A current instance of a limited tagged type, a protected type, a task type, or a type that has the reserved word limited in its full definition is also defined to be aliased. Finally, a formal parameter or generic formal object of a tagged type is defined to be aliased. Aliased views are the ones that can be designated by an access value. If the view defined by an object_declaration is aliased, and the type of the object has discriminants, then the object is constrained; if its nominal subtype is unconstrained, then the object is constrained by its initial value. Similarly, if the object created by an allocator has discriminants, the object is constrained, either by the designated subtype, or by its initial value.
!appendix

From: Tucker Taft
Sent: Wednesday, December 01, 1999 4:17 PM

Thanks to a posting on comp.lang.ada, I learned that our front end
was not enforcing a rule that only limited record types should allow
the use of T'Access or T'Unchecked_Access inside the type, because
only a limited type has an aliased "current instance."
In my attempt to add an enforcement for this rule, I ran into
a nasty situation. When do you decide whether a type is truly "limited"?
There are types that can become nonlimited later in their immediate scope,
because the full type of a component turns out to be nonlimited.
There are also cases where in a generic package a spec a type
looks limited, but from outside a particular instance, the type
looks nonlimited, because the "formally" limited components
were not "actually" limited.

Ultimately, I implemented a bit of a half-baked check.
When encountering the T'Access or T'Unchecked_Access during
the initial processing of a record type, if the type *might*
be limited then we allow it. Later, when an individual object
is created which causes the T'Access or T'Unchecked_Access to
be evaluated, if the type is not limited at that point, we complain.
This is clearly less than desirable.

To decide whether a record type "might" be limited, I use the following
information:
   1) if it is tagged, then it can only be limited if the ultimate
      ancestor (aka "root") type had the word "limited" in its definition.
   2) if it is the completion of a private type, then it can only
      be limited if the partial view was limited.

This leaves most untagged record types being considered "might be
limited" because when we encounter the T'[Unchecked_]Access, we might
not have seen all of the components (we haven't seen the ones that
come later in the record than the one with the use of T'Access), and one of
the components might turn out to be limited, rendering the whole
record limited. Of course, we could implement the check in a second
pass, or set a flag indicating that we saw a T'Access somewhere,
but then as mentioned above, the limitedness might disappear later
anyway.

This all seems pretty unsavory, and makes me want to suggest
that the rule should be that you may only use T'[Unchecked_]Access
inside an untagged record type if it explicitly uses the
word "limited" in its definition. This has the nice characteristic
that only types that are return-by-reference have an aliased
current instance. That's good, because if they are not return-by-reference,
(and not controlled), then the object is allowed to be copied and moved
around as part of a function return, which would render the use
of T'[Unchecked_]Access pretty meaningless.

The net effect of this is that certain programs would require
the addition of the word "limited" on a record type definition,
if there is a use of T'[Unchecked_]Access somewhere inside
the record type definition.  Note that *tagged* types already
effectively have this rule.

Another nice feature of this rule is that the use of T'Unchecked_Access
would have the same requirement as the rule for access
discriminants (3.7(10)) which requires the explicit use of
"limited."  These two rules are clearly related, and should
share the same kind of "limitedness" requirement.

The basic problem with the 3.10(9) rule as written now is that the
"limited"ness of a type can disappear if you don't use "limited"
explicitly, when you learn more about one of the components.
This makes correct enforcement much more difficult, and seems to
provide no benefit to the programmer.

Comments?

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

From: Ed Schonberg
Sent: Thursday, December 02, 1999 9:34 PM

>   Thanks to a posting on comp.lang.ada, I learned that our front end
>   was not enforcing a rule that only limited record types should allow
>   the use of T'Access or T'Unchecked_Access inside the type, because
>   only a limited type has an aliased "current instance."

Interesting, I just went through the same exercise, not doubt motivated by
a report from the same source...

>  In my attempt to add an enforcement for this rule, I ran into
>  a nasty situation.  When do you decide whether a type is truly "limited"?

It would seem that the place at which the type is frozen is a good place.
At least this is where we do it. It appears that no further information
about the components should matter after that point. Is this semantically
incorrect?  In GNAT this choice also means that we don't apply the check to
a type defined in a generic unit, only to the corresponding type in an
instance. Again, are were deviating from the intent? In any case, it means
that while processing the record declaration we accept the 'Access conditiona-
lly, and have to make a separate pass over the declaration at the freezing
point (it has to be done anyway to freeze the component types).

>  ..  the rule should be that you may only use T'[Unchecked_]Access
>  inside an untagged record type if it explicitly uses the
>  word "limited" in its definition.  This has the nice characteristic
>  that only types that are return-by-reference have an aliased
>  current instance.  That's good, because if they are not return-by-reference,
>  (and not controlled), then the object is allowed to be copied and moved
>  around as part of a function return, which would render the use
>  of T'[Unchecked_]Access pretty meaningless.
>
>  The net effect of this is that certain programs would require
>  the addition of the word "limited" on a record type definition,
>  if there is a use of T'[Unchecked_]Access somewhere inside
>  the record type definition.  Note that *tagged* types already
>  effectively have this rule.
>
>  Another nice feature of this rule is that the use of T'Unchecked_Access
>  would have the same requirement as the rule for access
>  discriminants (3.7(10)) which requires the explicit use of
>  "limited."  These two rules are clearly related, and should
>  share the same kind of "limitedness" requirement.

>  The basic problem with the 3.10(9) rule as written now is that the
>  "limited"ness of a type can disappear if you don't use "limited"
>  explicitly, when you learn more about one of the components.
>  This makes correct enforcement much more difficult, and seems to
>  provide no benefit to the programmer.

I agree that there is no particular benefit to the current rule, the
keyword should be required, the programmer has to know that the
type is limited, he might as well say so!

Ed Schonberg

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

From: Pascal Leroy
Sent: Friday, December 03, 1999 4:24 AM

> >  In my attempt to add an enforcement for this rule, I ran into
> >  a nasty situation.  When do you decide whether a type is truly "limited"?
>
> It would seem that the place at which the type is frozen is a good place.

Performing this type of check at the freezing point is possible, but I find it
distasteful, as it tends to break privateness and the linear compilation
model.

Surely at the freezing point you know the completion of all the types
involved, but it can be the case that a type becomes nonlimited _after_ its
freezing point.  So you need to either (1) assume-the-worst or (2) determine
if there will be a point in the future where the type becomes nonlimited.  If
you choose (1), I don't see much benefit in delaying the check until the
freezing point; if you choose (2) the check becomes rather complicated and can
have counter-intuitive consequences (eg the absence/presence of a body
influencing the legality of T'Access).

> >  ..  the rule should be that you may only use T'[Unchecked_]Access
> >  inside an untagged record type if it explicitly uses the
> >  word "limited" in its definition.

I agree, that's the right way to fix this problem.  It can break existing
code, but that's rather pathological code, and it's not portable anyway
because different compilers seem to do different things today.

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

From: Randy Brukardt

In writing up this AI, I borrowed wording from RM 7.5(4), rather than using
Tucker's "explicitly includes".

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

Questions? Ask the ACAA Technical Agent