Version 1.4 of ais/ai-00385.txt

Unformatted version of ais/ai-00385.txt version 1.4
Other versions for file ais/ai-00385.txt

!standard 03.03.01 (02)          05-03-23 AI95-00385/04
!standard 03.03.01 (08)
!standard 03.03.01 (16)
!standard 03.10.02 (11)
!standard 07.04 (05)
!class amendment 04-10-25
!status Amendment 200Y 04-12-01
!status ARG Approved 8-1-1 04-11-19
!status work item 04-10-25
!status received 04-10-25
!priority High
!difficulty Medium
!subject Stand-alone objects of anonymous access types
!summary
Stand-alone objects of an anonymous access type are introduced.
!problem
AI-230 introduced anonymous access types in wider contexts than just access parameters and discriminants. An important goal was to permit more flexible use of access types in object oriented programming and in particular to reduce the need for type conversions which can be tiresome when named access types are used.
However, although anonymous access types were introduced for components of arrays and records and for renaming, they were not permitted for stand-alone variables because it was felt that the accessibility rules might be confusing.
It was argued moreover that access objects mostly appear as components (linked lists are typical). However, stand-alone objects still occur from time to time and these have to be of a named type and essentially unnecessary explicit conversions therefore still arise. These could of course be avoided by wrapping single variables in a record but that seems foolish.
It is now considered that disallowing stand-alone variables was a mistake and is likely to lead to frustration, anger and derision on the part of users.
!proposal
It is proposed that stand-alone objects be permitted of an anonymous access type. We also need to allow deferred constants to be of an anonymous access type, by extending their matching rules.
!wording
Replace 3.3.1(2) by
object_declaration ::= defining_identifier_list : [aliased] [constant] subtype_indication [:= expression] | defining_identifier_list : [constant] access_definition [:= expression] | defining_identifier_list : [aliased] [constant] array_type_definition [:= expression] | single_task_declaration | single_protected_declaration
Modify 3.3.1(8)
The subtype_indication{, access_definition,} or full type definition of an object declaration ...
Modify 3.3.1(16)
1. The subtype_indication{, access_definition}, array_type_definition,
single_task_declaration, or single protected_declaration is first elaborated. This creates the nominal subtype (and the anonymous type in the [latter three]{last four} cases.
[Editor's note: Fowler says former and latter should only be used when there are just two cases, thus the word is changed to last.]
Add after 3.10.2(11)
The accessibility level of the anonymous access type defined by an access_definition of an object_declaration is the same as that of the declared object.
Modify 7.4(5)
The deferred and full constants shall have the same type{, or shall have statically matching anonymous access subtypes}.
Change the start of 7.4(6) to
If the deferred constant declaration includes a subtype_indication that defines a constrained subtype, ...
!discussion
The restriction on access variables was found to be frustrating when starting to write the Rationale for Ada 2005. It was a delight to be able to say that we can declare
type Cell is record Next: access Cell; Value: Integer; end;
and therefore avoid the circumlocution of having to write
type Cell; type Cell_Ptr is access Cell;
type Cell is
record
Next: Cell_Ptr; Value; Integer;
end record;
As an aside, AI-382 had to be written and approved in order to permit the component of type access Cell because normally the use of a type name in a record always refers to the current instance.
Having overcome that difficulty we find that the poor user cannot write
The_List: access Cell;
but still has to write
The_List: Cell_Ptr;
in order to refer to the list as a whole. Moreover, if we want to copy the value in the component Next into a stand-alone variable such as The_Tail (also of type Cell_Ptr) then we have to do a type conversion thus
The_List := Cell_Ptr(The_List.Next);
and we are in effect worse off than before.
We will now look at the reasons given in AI-230 for the restriction disallowing stand-alone objects of anonymous access types.
AI-230 says
We considered allowing anonymous access types in stand-alone variable declarations. However the general philosophy for accessibility levels (described above in the proposal section) would force them to have a level determined by their declaration rather than initial value. This might create confusion when copying an access parameter into a local variable and unintentionally losing the accessibility level information. By only allowing renamings, and having them preserve the accessibility level information, we avoid this possible problem. Because allowing constants but not variables introduced a non-orthogonality, we chose to allow renamings which can be used in most cases where a constant would have been useful.
As an alterantive (sic), we considered allowing variables of an anonymous access type to carry run-time accessibility levels across assignment statements with an accompanying accessibility check as well to handle up-level assignments. But this would totally change the model, since in all other cases we have fully determined the accessibility level at the point of the elaboration of the anonymous access type.
There is no dispute with the second paragraph; requiring dynamic accessibility information would indeed completely change the model. Users are familiar with the idea that access parameters carry dynamic information but are also aware that access parameters are somewhat special.
Returning to the first paragraph, the first point is that stand-alone variables would require an accessibility level determined by their declaration and not their initial value. That seems totally as expected. Indeed it would be peculiar if it were not since that would imply that such a variable without an initial value could have a different accessibility level to one with an initial value - that would indeed be very strange.
It then claims that confusion might arise when assigning an access parameter to a stand-alone variable. It is hard to see why this should inevitably be concluded. Users are familiar with the idea that access parameters are special and should not be surprised if assigning a value from one might not change some information. On the other hand the idea that a renaming just provides another view of the same entity and thus preserves the accessibility level is perfectly within accepted Ada principles.
The final point concerns constants. It is stated that having constants and not variables would be a nasty non-orthogonality and so renaming was permitted as an alternative to constants. However, surely it is a much nastier non-orthogonality to permit record and array components and not stand-alone variables.
One argument for not allowing constants is the potential confusion between
ACT: access constant T := ... CAT: constant access T := ...
The first would mean that ACT is a variable which can access different objects of type T but cannot change the values of the objects.
The second would mean that CAT is a constant and so its value cannot change and therefore it cannot access different objects. However the value of the object can be changed by a dereferenced assignment such as CAT.all := ...;
It is claimed that this is confusing (the author thinks this is blindingly obvious to anyone who can spell Ada and reads from left to right) but has been told that it might confuse C folk who have T and T the other way around).
A stronger point is that it is considered dangerous that the reversal of two words should make such a lot of difference. However, there are other places in the language where small changes have a dramatic effect (for example, replacing or by else in a timed entry call).
It is instructive to compare the following using named access types. In one case we write
type CT is access constant T; ACT: CT;
and in the other case we have
type at is access T; CAT: constant at;
By separating the two stages of declaration the applicability of "constant" is more obvious.
If we feel strongly about the possible confusion between constant access and access constant then we can permit the latter but not the former. That is we forbid a constant of an anonymous access type. In terms of the danger of getting it wrong it is clear that this is the safe way around. It is better to protect the object being referred to.
There would seem however to be no real reason why we could not allow
CACT: constant access constant T;
but in order to preserve more orthogonality, this too would be forbidden in this scenario.
So we are faced with three choices:
1) reject this AI
We then have to live with the non-orthogonality that stand-alone variables are not permitted. This will annoy many programmers and educators.
2) permit both stand-alone variables and constants
This preserves the orthogonality and will be what programmers expect. There is some risk that some programmers will make errors.
3) compromise and permit stand-alone variables but not constants
This provides the variables that everyone expects but reduces the risk of errors with constants at the expense of introducing a surprising non- orthogonality.
Moreover, some style guides insist on the use of constants and there is evidence that some compilers are able to generate better code for constants.
After much discussion it was decided to chose option 2.
!example
(See discussion.)
!corrigendum 03.03.01(2)
Replace the paragraph:
object_declaration ::= defining_identifier_list : [aliased] [constant] subtype_indication [:= expression] | defining_identifier_list : [aliased] [constant] array_type_definition [:= expression] | single_task_declaration | single_protected_declaration
by:
object_declaration ::= defining_identifier_list : [aliased] [constant] subtype_indication [:= expression] | defining_identifier_list : [constant] access_definition [:= expression] | defining_identifier_list : [aliased] [constant] array_type_definition [:= expression] | single_task_declaration | single_protected_declaration
!corrigendum 03.03.01(8)
Replace the paragraph:
The subtype_indication or full type definition of an object_declaration defines the nominal subtype of the object. The object_declaration declares an object of the nominal subtype.
by:
The subtype_indication, access_definition, or full type definition of an object_declaration defines the nominal subtype of the object. The object_declaration declares an object of the nominal subtype.
!corrigendum 03.03.01(16)
Replace the paragraph:
1.
The subtype_indication, array_type_definition, single_task_declaration, or single_protected_declaration is first elaborated. This creates the nominal subtype (and the anonymous type in the latter three cases).
by:
1.
The subtype_indication, access_definition, array_type_definition, single_task_declaration, or single_protected_declaration is first elaborated. This creates the nominal subtype (and the anonymous type in the last four cases).
!comment AI-416 considers this redundant.
!comment !corrigendum 3.10.2(11)
!comment
!comment @dinsa
!comment @xbullet<The accessibility level of a derived access type is that of
!comment its ultimate ancestor.>
!comment @dinss
!comment @xbullet<The accessibility level of the anonymous access type
!comment defined by an @fa<access_definition> of an @fa<object_declaration> is
!comment the same as that of the declared object.>
!corrigendum 7.4(5)
Replace the paragraph:
by:
!corrigendum 7.4(6)
Replace the paragraph:
by:
!ACATS test
Tests should be created to check on the implementation of this feature.
!appendix

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

Questions? Ask the ACAA Technical Agent