!standard 3.10 (06) 04-05-24 AI95-00231/09 !standard 3.2.3 (03) !standard 3.2.3 (05) !standard 3.7 (05) !standard 3.7 (09) !standard 3.10 (02) !standard 3.10 (12) !standard 3.10 (13) !standard 3.10 (14/1) !standard 3.10 (15) !standard 4.2 (07) !standard 4.6 (49) !standard 4.6 (51) !standard 4.9.1 (02) !standard 6.1 (15) !standard 6.1 (23) !standard 6.1 (24) !standard 8.5.1 (04) !standard 8.6 (25) !standard 12.5.1 (10) !standard 12.5.4 (04) !class amendment 00-04-13 !status Amendment 200Y 04-01-09 !status ARG Approved 10-0-1 03-12-13 !status work item 00-04-13 !status received 00-04-13 !priority Medium !difficulty Hard !subject Access-to-constant parameters and null-excluding access subtypes !summary Parameters and discriminants of an anonymous access-to-constant type are introduced. Non-controlling access parameters and access discriminants are changed to allow having a null value by default, but allow null to be excluded explicitly. Null-excluding subtypes of a named access type are introduced. !problem (See discussion.) !proposal Change non-controlling access parameters and access discriminants to allow them to have null values. This represents a return to the original Ada 83 model where all access types include a null value. Allow the notion of a null-excluding access subtype, by introducing a a "null exclusion" ("not null"), and allow it on subtype indications, access type definitions, and access definitions. We don't call it a "constraint" because doing so creates various wording issues relating to "constrained" versus "unconstrained". Generalize access_definition to allow specification of access-to-constant and a null exclusion for anonymous access types. !wording Replace paragraph 3.2.2(3) with: subtype_indication ::= [null_exclusion] subtype_mark [scalar_constraint | composite_constraint] Delete paragraph 3.2.2(5). Modify 3.7(5) to: discriminant_specification ::= defining_identifier_list : [null_exclusion] subtype_mark [:= default_expression] | defining_identifier_list : access_definition [:= default_expression] Modify the first sentence of 3.7(9): The subtype of a discriminant may be defined by {an optional null_exclusion and} a subtype_mark, in which case the subtype_mark shall denote a discrete or access subtype, .... is of an anonymous [general access-to-variable] {access} type [whose designated subtype is denoted by the subtype_mark of the access_definition]. Modify 3.10(2) to: access_type_definition ::= [null_exclusion] access_to_object_definition | [null_exclusion] access_to_subprogram_definition Modify 3.10(6) to: null_exclusion ::= NOT NULL access_definition ::= [null_exclusion] ACCESS [general_access_modifier] subtype_mark Modify 3.10(12) to: An access_definition defines an anonymous general access type; the subtype mark denotes its designated subtype. If the word constant appears, the type is an access-to-constant type; otherwise it is an access-to-variable type. If a null_exclusion is present, or the access_definition is for a controlling access parameter (see 3.9.2), the access_definition defines an access subtype which excludes the null value; otherwise the subtype includes a null value. An access_definition is used in the specification of an access discriminant (see 3.7) or an access parameter (see 6.1). [NOTE: Drop this last sentence if AI-230 is approved.] AARM Note: Controlling access_definitions are null-excluding because it is necessary to read the tag to dispatch, and null has no tag. We would have preferred to require not null to be specified for such parameters, but that would have been too incompatible with Ada 95. Modify 3.10(13) as follows: For each [(named)] access type, there is [a literal null which has] a null access value designating no entity at all. The null value of [a named] {an} access type is the ... in the case of [a named] {an} access-to-object type, an allocator, which returns ... Add the following sentence to the end of 3.10(14/1): The first subtype of a type defined by an access_type_definition excludes the null value if a null_exclusion is present; otherwise, the first subtype includes the null value. Add after 3.10(14/1): Legality Rules A null_exclusion is only allowed in a subtype_indication whose subtype_mark denotes an access subtype that includes a null value. Modify 3.10(15) as follows: A composite_constraint is compatible with an unconstrained access subtype if it is compatible with the designated subtype. {A null_exclusion is compatible with any access subtype that includes a null value.} An access value satisfies a composite_constraint of an access subtype if it equals the null value of its type or if it designates an object whose value satisfies the constraint. {An access value satisfies a null_exclusion imposed on an access subtype if it does not equal the null value of its type.} Delete paragraph 4.2(7) which says that anonymous access types don't have a null value. Replace 4.6(49) with: If the operand value is null, the result of the conversion is the null value of the target type. Add to the end of 4.6(51): If the target subtype excludes the null value, then a check is made that the value is not null. Change 4.9.1(2): A subtype statically matches another subtype of the same type if they have statically matching constraints{, and, for access subtypes, either both or neither exclude null}. Two anonymous access{-to-object} subtypes statically match if their designated subtypes statically match{, and either both or neither exclude null, and either both or neither are access-to-constant}. Modify 6.1(15): parameter_specification ::= defining_identifier_list : mode [null_exclusion] subtype_mark [:= default_expression] | defining_identifier_list : access_definition [:= default_expression ] Modify 6.1(23): The nominal subtype of a formal parameter is the subtype [denoted] {determined} by the {optional null_exclusion and the} subtype_mark, or defined by the access_definition, in the parameter_specification. Modify 6.1(24): .... An access parameter is of an anonymous [general access-to-variable] {access} type (see 3.10). ... Add to the end of 8.5.1(4), if AI-230 is adopted: In the case where the type is defined by an access_definition, the renamed entity shall be of an access-to-constant type if and only if the access_definition defines an access-to-constant type. Modify 8.6(25): * when T is an anonymous access{-to-object} type (see 3.10) with designated type D, to an access-to-[variable]{object} type whose designated type is D'Class or is covered by D{, and that is access-to-constant only if T is access-to-constant}. Add after 12.5.1(10) * If the ancestor subtype is an access subtype, the actual subtype shall exclude null if and only if the ancestor subtype excludes null. Add to the end of 12.5.4(4): If and only if the formal subtype excludes null, the actual subtype shall exclude null. !example type Non_Null_Ptr is not null access T; procedure Show(X : Non_Null_Ptr); -- X guaranteed to not be null procedure Pass_By_Ref(Y : not null access constant Rec); -- Pass Y.all by reference, but don't allow it to be updated; -- Guarantee Y is non-null. procedure Display(W : access Window; G : access constant Graph'Class); -- Allow any pointer to a graph to be passed to the window -- display routine; allow null to be passed as well. !discussion It is surprising that an access-to-constant parameter/discriminant is not available. There are several circumstances where such a parameter/discriminant would be appropriate: As a controlling parameter of an operation that doesn't modify the designated object. As a way to force pass-by-reference when interfacing with a foreign language, when the external operation does not update the designated object, As a way to provide read-only access via a discriminant. The rule disallowing "null" for access parameters and access discriminants has turned out to be confusing, and not what is wanted in all cases when interfacing with a foreign language. Therefore, we propose to revert to the Ada 83 model where all access types include a null value, and to define an explicit way to exclude nulls from an access subtype. "Access T" and "access constant T" will include nulls by default (when not a controlling parameter), even though this does not preserve complete upward compatibility. Note that the only incompatibility is for cases where null was passed, and these would have been rejected at compile-time or have raised Constraint_Error. It was felt it was better to have this upward incompatibility than to have the default be null-excluding for "access T" but not null-excluding for "access constant T". Note that there is no upward incompatibility for controlling access parameters; they always have null-excluding subtypes. Any worrisome loss of efficiency due to allowing null for non-controlling access parameters, or access discriminants, can be reversed by using an explicit null_exclusion. (It would be easy to create a tool that added needed null_exclusions to Ada 95 programs.) The general ability to specify an access subtype that excludes null for both named and anonymous access types can provide useful documentation and higher efficiency. This is especially true for parameters, by allowing the nullness check to be "pushed" to the caller, where it can be more likely removed. What should be the default initialization of an object of a subtype that excludes null? It seems clear that the default is still null, and the initialization will raise Constraint_Error. Hence, objects of such a subtype will require explicit initialization in order to be useful. Note that the "all" in an access_definition is redundant, since anonymous access types are always considered "general" access types. However, it was felt more confusing to disallow use of "all" for anonymous access types, even though it has no effect. We chose to require matching of null exclusion in generics. For formal derived types, static constraint matching was already the case for access subtypes. For formal access types, we claim that the paradigm of use for null-excluding access types differs dramatically from null-including access types, and hence it is not sensible to allow the formal and actual to differ on this dimension. It also significantly simplifies generic sharing if null exclusion is known statically. Note that we do not allow a null exclusion to be applied to an already null-excluding subtype. This is analogous to the restriction against reconstraining non-scalar subtypes. Given that we require matching of null exclusion in generics, it will always be known statically whether a given subtype excludes null, so there seems no reason to allow "confirming" null exclusions. Just as likely it might represent a confusion on the part of the programmer, so disallowing it might help detect such confusion. We discussed situations where you might want a single generic to be usable with both null including and null excluding actual subtypes. However, if one has a generic whose formal includes null, and one wants to reuse it with an access subtype that excludes null, you can do the instantiation using a null-including subtype of the same access type and accomplish the same level of reuse. A major advantage of requiring the actual to include null if the formal does is that the generic can still declare default-initialized local variables of the access type, without bumping into the null exclusion. The instantiatior only cares about null exclusion on values returned from the instance, and these checks would still be performed as part of assigning a returned value to a variable of a null-excluding subtype. Forcing the generic itself to operate internally obeying null exclusion would make it that much harder to reuse the generic. For example: generic with type Designated_Type is limited private; with type Formal_Acc is access Designated_Type; procedure Gen(Ptr : in out Formal_Acc); procedure Gen(Ptr : in out Formal_Acc) is Local : Formal_Acc; -- defaults to null begin Local := new Designated_Type; if Ptr /= null then Ptr := Local; end if; end Gen; type Acc_With_Null is access T; subtype Acc_Non_Null is non null Acc_With_Null; procedure Instance is new Gen(Acc_With_Null); -- Instantiate with null-including subtype Y : Acc_Non_Null := new T; begin Instance(Ptr => Y); Inside Gen, "Ptr" and other objects of type "Formal_Acc" (e.g. "Local") can take on null values. However, on return from the call, if the actual associated with "Ptr" is of a null-excluding subtype, then the appropriate check for null will be performed. The instantiator doesn't care if somewhere inside "Gen" there are pointers that are temporarily null. (Note that this works because parameters of an access type use pass-by-copy. This approach would not work if access values were passed by reference.) Note that the complementary requirement is also important, namely that if the formal excludes null, then so should the actual. This allows the code inside the generic to assume that any object or component that is of the formal type is non-null, even if it is passed from outside the generic. Hence, we require matching both ways, namely the actual may exclude null if and only if the formal excludes null. [Note: In the !corrigendum wording below, we assume that AI-230 is also approved.] !corrigendum 3.2.2(3) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 3.2.2(5) @ddel @xcode<@fa> !corrigendum 3.7(5) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 3.7(9) @drepl The subtype of a discriminant may be defined by a @fa, in which case the @fa shall denote a discrete or access subtype, or it may be defined by an @fa (in which case the @fa of the @fa may denote any kind of subtype). A discriminant that is defined by an @fa is called an @i and is of an anonymous general access-to-variable type whose designated subtype is denoted by the @fa of the @fa. @dby The subtype of a discriminant may be defined by an optional @fa and a @fa, in which case the @fa shall denote a discrete or access subtype, or it may be defined by an @fa (in which case the @fa of the @fa may denote any kind of subtype). A discriminant that is defined by an @fa is called an @i and is of an anonymous access type. !corrigendum 3.10(2) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 3.10(6) @drepl @xcode<@fa@ft<@b>@fa< subtype_mark>> @dby @xcode<@fa@ft<@b> @fa@ft<@b>@fa< [general_access_modifier] subtype_mark>> !corrigendum 3.10(12) @drepl An @fa defines an anonymous general access-to-variable type; the @fa denotes its @i. An @fa is used in the specification of an access discriminant (see 3.7) or an access parameter (see 6.1). @dby An @fa defines an anonymous general access type; the @fa denotes its @i. If the reserved word @b appears, the type is an access-to-constant type; otherwise it is an access-to-variable type. If a @fa is present, or the @fa is for a controlling access parameter (see 3.9.2), the @fa defines an access subtype which excludes the null value; otherwise the subtype includes a null value. !corrigendum 3.10(13) @drepl For each (named) access type, there is a literal @b which has a null access value designating no entity at all. The null value of a named access type is the default initial value of the type. Other values of an access type are obtained by evaluating an @fa for the Access or Unchecked_Access attribute of an aliased view of an object or non-intrinsic subprogram, or, in the case of a named access-to-object type, an @fa, which returns an access value designating a newly created object (see 3.10.2). @dby For each access type, there is a null access value designating no entity at all. The null value of an access type is the default initial value of the type. Other values of an access type are obtained by evaluating an @fa for the Access or Unchecked_Access attribute of an aliased view of an object or non-intrinsic subprogram, or, in the case of an access-to-object type, an @fa, which returns an access value designating a newly created object (see 3.10.2). !corrigendum 3.10(14/1) @drepl All subtypes of an access-to-subprogram type are constrained. The first subtype of a type defined by an @fa or an @fa is unconstrained if the designated subtype is an unconstrained array or discriminated subtype; otherwise it is constrained. @dby All subtypes of an access-to-subprogram type are constrained. The first subtype of a type defined by an @fa or an @fa is unconstrained if the designated subtype is an unconstrained array or discriminated subtype; otherwise it is constrained. The first subtype of a type defined by an @fa excludes the null value if a @fa is present; otherwise, the first subtype includes the null value. @i<@s8> A @fa is only allowed in a @fa whose @fa denotes an access subtype that includes a null value. !corrigendum 3.10(15) @drepl A @fa is @i with an unconstrained access subtype if it is compatible with the designated subtype. An access value @i a @fa of an access subtype if it equals the null value of its type or if it designates an object whose value satisfies the constraint. @dby A @fa is @i with an unconstrained access subtype if it is compatible with the designated subtype. A @fa is compatible with any access subtype that includes a null value. An access value @i a @fa of an access subtype if it equals the null value of its type or if it designates an object whose value satisfies the constraint. An access value satisifes a @fa imposed on an access subtype if it does not equal the null value of its type. !corrigendum 4.2(7) @ddel A literal @fa shall not be of an anonymous access type, since such types do not have a null value (see 3.10). !corrigendum 4.6(49) @drepl @xinbull @dby @xinbull !corrigendum 4.6(51) @drepl After conversion of the value to the target type, if the target subtype is constrained, a check is performed that the value satisfies this constraint. @dby After conversion of the value to the target type, if the target subtype is constrained, a check is performed that the value satisfies this constraint. If the target subtype excludes the null value, then a check is made that the value is not null. !corrigendum 4.9.1(2) @drepl A subtype @i another subtype of the same type if they have statically matching constraints. Two anonymous access subtypes statically match if their designated subtypes statically match. @dby A subtype @i another subtype of the same type if they have statically matching constraints, and, for access subtypes, either both or neither exclude null. Two anonymous access-to-object subtypes statically match if their designated subtypes statically match, and either both or neither exclude null, and either both or neither are access-to-constant. !corrigendum 6.1(15) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 6.1(23) @drepl The nominal subtype of a formal parameter is the subtype denoted by the @fa, or defined by the @fa, in the @fa. @dby The nominal subtype of a formal parameter is the subtype determined by the optional @fa and the @fa, or defined by the @fa, in the @fa. !corrigendum 6.1(24) @drepl An @i is a formal @b parameter specified by an @fa. An access parameter is of an anonymous general access-to-variable type (see 3.10). Access parameters allow dispatching calls to be controlled by access values. @dby An @i is a formal @b parameter specified by an @fa. An access parameter is of an anonymous access type (see 3.10). Access parameters allow dispatching calls to be controlled by access values. !corrigendum 8.5.1(4) @drepl The renamed entity shall be an object. @dby The renamed entity shall be an object. In the case where the type is defined by an @fa, the renamed entity shall be of an access-to-constant type if and only if the @fa defines an access-to-constant type. !corrigendum 8.6(25) @drepl @xinbull is an anonymous access type (see 3.10) with designated type @i, to an access-to-variable type whose designated type is @i'Class or is covered by @i.> @dby @xinbull is an anonymous access-to-object type (see 3.10) with designated type @i, to an access-to-object type whose designated type is @i'Class or is covered by @i, and that is access-to-constant only if @i is access-to-constant.> !corrigendum 12.5.1(10) @dinsa @xbullet @dinst @xbullet !corrigendum 12.5.4(4) @drepl If and only if the @fa @b applies to the formal, the actual shall be an access-to-constant type. If the @fa @b applies to the formal, then the actual shall be a general access-to-variable type (see 3.10). @dby If and only if the @fa @b applies to the formal, the actual shall be an access-to-constant type. If the @fa @b applies to the formal, then the actual shall be a general access-to-variable type (see 3.10). If and only if the formal subtype excludes null, the actual subtype shall exclude null. !ACATS test Tests should be created to check on the implementation of this feature. !appendix Randy Brukardt 00-04-13 This proposal was split out of the "with type" proposal (AI-00217) in April 2000. Some early conversation on this feature can be found in that AI's appendix. ************************************************************* !topic Missing change in AI95-00231 !reference AI95-00231, RM95 6.1(24) !from Adam Beneschan 09-30-02 !discussion Nitpick du jour: I just noticed AI95-00231, which proposes that, among other things, ACCESS CONSTANT be allowed as a subprogram access parameter. It appears that in the list of RM changes for this AI, 6.1(24) was missed. This paragraph includes the sentence: "An access parameter is of an anonymous general access-to-variable type (see 3.10)." which will no longer be true since the access parameter could now be an access-to-constant type. ************************************************************* From: Dan Eilers Sent: Friday, January 17, 2003 2:41 PM AI-231 proposes the syntax: not_null_constraint ::= NOT NULL for null-excluding subtypes of a named access type. I propose generalizing this to allow value-excluding subtypes of other named types, serving the same purpose: > The general ability to specify an access subtype that excludes null for both > named and anonymous access types can provide useful documentation and higher > efficiency. This is especially true for parameters, by allowing the nullness > check to be "pushed" to the caller, where it can be more likely removed. The same principle applies to the division-by-zero check. not_constraint ::= NOT NULL not_constraint ::= NOT 0 not_constraint ::= NOT 0.0 not_constraint ::= NOT Friday ************************************************************* From: Robert Dewar Sent: Sunday, January 19, 2003 8:42 AM While I am a little sympathetic to the non-null access type proposal, I find Dan's proposal for extending it definitely inappropriate. It sounds like a lot of extra work to specify and implement. ************************************************************* From: Tucker Taft Sent: Tuesday, May 6, 2003 2:49 PM During the AdaUK Ada 200Y workshop, Franco Gasperoni made a good suggestion. He felt it will be too confusing to make "access T" mean "access all T not null" (I think others have made this point as well). Why not just change the semantics of "access T" to allow null (though when used as a controlling operand, there will be a run-time check for non-null), so that "access all T" and "access T" are synonyms. This will be upward compatible for programs that don't raise Constraint_Error, and the slight potential performance degradation when the non-null aspect of access T was important can be made up for by using "not null" explicitly. This seems like a reasonable suggestion, and is probably one we have debated in the past, and just were perhaps worried about the compatibility issue. But in fact, I suspect this is the kind of thing that may fix more bugs that it creates. Most uses of anon access types are for controlling operands, and those will see no change. The other uses often discover a need to pass "null" eventually, and then have to switch to a named access type, or play some other game. Certainly when interfacing with C or Java, an "access T" that allows null will be more useful. And altough we could say that "access T" is just a convenient shorthand for "access all T not null" it does seem like a recipe for confusion when teaching Ada 200Y. It seems like if the non-null aspect of an access parameter is important, users will welcome the chance to say "not null" explicitly. ************************************************************* From: John Barnes Sent: Thursday, May 8, 2003 1:28 AM Good idea.. I always hated the potential confusion as it was. ************************************************************* From: Gary Dismukes Sent: Tuesday, May 13, 2003 6:33 AM I agree that this seems like a sensible change with minimal disadvantages. ************************************************************* From: Robert A Duff Sent: Thursday, May 8, 2003 7:34 AM Me, three. ************************************************************* From: Randy Brukardt Sent: Saturday, September 27, 2003 6:15 PM In the appendix of AI-231, I see a note from Adam Beneschan that 6.1(24) will need to be changed (because it says "access-to-variable"). I think the AI needs to include that, right? ************************************************************* From: Randy Brukardt Sent: Saturday, September 27, 2003 6:17 PM 3.7(9) has the same wording, and will need a similar fix. ************************************************************* From: Tucker Taft Sent: Sunday, September 28, 2003 9:09 AM Good point. Can you make those fixes, or do you want another version from me? ************************************************************* From: Randy Brukardt Sent: Monday, September 29, 2003 6:02 PM The wording change isn't instantly obvious, so I think I'd prefer a new version from you. ************************************************************* From: Javier Miranda Sent: Wednesday, January 7, 2004 12:29 PM In file AI-00231.TXT (date 03-10-22) it is said: access_definition ::= [null_exclussion] ACCESS general_access_modifier subtype_mark However, in AI-00254 (date 03-11-11) it is said: access_definition ::= [null_exclussion] ACCESS [general_access_modifier] subtype_mark | ... It seems to me that this second alternative is the right one (to be compatible with Ada95). In addition both proposals should have the same rule. Is this a bug in AI-00231? ************************************************************* From: Gary Dismukes Sent: Wednesday, January 7, 2004 1:00 PM This looks like a bug in AI-00231. Certainly there's no intent to create an incompatibility by requiring an explicit modifier. ************************************************************* From: Randy Brukardt Sent: Wednesday, January 7, 2004 10:26 PM The version that Tucker handed out at the meeting (AI-00231/07) doesn't have this problem. I didn't post it in the hopes of saving redundant effort, but it is now available in the version control system (only - not in the .ZIP files). ************************************************************* From: Javier Miranda Sent: Thursday, January 8, 2004 3:33 AM Thanks Randy. In the future I will use the versions available in the version control system to avoid generating unnecessary noise! ************************************************************* From: Randy Brukardt Sent: Thursday, January 8, 2004 11:55 AM That's always preferrable, but it wouldn't have helped in this case, because I didn't actually send the changes up until I saw your note. So only people who were at the meeting had the new version. *************************************************************