Version 1.11 of ai12s/ai12-0342-1.txt

Unformatted version of ai12s/ai12-0342-1.txt version 1.11
Other versions for file ai12s/ai12-0342-1.txt

!standard 4.2.1(0)          21-07-14 AI12-0342-1/07
!standard 3.9.2(1/2)
!standard 6.3.1(22)
!reference AI12-0249-1
!reference AI12-0295-1
!reference AI12-0325-1
!class Amendment 19-09-10
!status Amendment 1-2012 20-01-15
!status ARG Approved 9-0-4 20-01-15
!status work item 19-09-10
!status received 19-08-15
!priority Low
!difficulty Easy
!subject Various issues with user-defined literals (part 2)
!summary
The aspects related to user-defined literals are inheritable.
The "a literal is equivalent to a call" equivalence is extended from just dynamic semantics into static semantics.
Conformance rules are tightened up for user-defined literals.
!problem
There are a number of issues with definition of user-defined literals (even after AI12-0325, which is the "part 1" implicitly referred to in the !subject text).
!proposal
This AI is about two topics:
1) Inheritance of Integer_Literal, Real_Literal, and String_Literal
aspects. These aspects are inherited according to the rules given in 13.1. In the case of type extension, any such inherited aspects must be overridden.
2) Treating a user-defined literal like a function call for purposes of
static semantics, not just dynamic semantics. This is intended to clarify, for example, the rules about how user-defined literals interact with abstract types and abstract subprograms.
A minor hole in the 6.3.1 conformance rules is also addressed.
!wording
Modify the first sentence of 3.9.2(1/2):
The primitive subprograms of a tagged type, the subprograms declared by formal_abstract_subprogram_declarations, {the subprograms identified by the user-defined literal aspects of a specific tagged type (see 4.2.1),} and the stream attributes of a specific tagged type that are available (see 13.13.2) at the end of the declaration list where the type is declared are called dispatching operations.
Modify 4.2.1(2/5):
The following [nonoverridable, ]type-related operational aspects {(collectively known as user-defined literal aspects)} may be specified for a type T:
In 4.2.1(3/5, 4/5, and 5/5), replace (once in each)
"that denotes a primitive function of T" with "that statically denotes a
function"
Append after 4.2.1 (5/5) (at the end of the Static Semantics section)
AARM Ramification:
The following example is legal because the resolution of an aspect_definition for an aspect that is defined to be a subprogram is based on the profile required for that aspect (see 13.1.1):
package Pkg1 is type T is record X, Y : Integer; end record with Integer_Literal => Int_Lit; function Int_Lit (X, Y : T) return Duration; -- wrong profile function Int_Lit (Lit_Image : String) return T; -- right profile end;
End AARM Ramification.
User-defined literal aspects are inherited according to the rules given in 13.1.
AARM Discussion:
This means that in this example
package Pkg is type T1 is record X, Y : Integer; end record with Integer_Literal => I_L;
function I_L (S : String) return T1 is ((0, 0));
type T2 is new T1; function I_L (S : String) return T2 is ((1, 1)); X : T2 := 123; end Pkg;
the initial value of Pkg.X is (0,0), not (1,1). End AARM Discussion.
When a numeric literal is interpreted as a value of a non-numeric type T or a string_literal is interpreted as a value of a type T that is not a string type (see 4.2), it is equivalent to a call to the subprogram denoted by the corresponding aspect of T: the Integer_Literal aspect for an integer literal, the Real_Literal aspect for a real literal, and the String_Literal aspect for a string_literal. The actual parameter of this notional call is a string_literal having the textual representation of the original (numeric or string) literal.
AARM Discussion: This equivalence defines, for example, the nominal type, the nominal subtype, and the accessibility level of a user-defined literal. It also has the consequence that a user-defined literal shall not be of an abstract type (because that would be equivalent to a nondispatching call to an abstract function). This equivalence also defines the dynamic semantics of evaluating a user-defined literal.
The (sub)type of the actual parameter to this call is determined by the profile of the appropriate aspect, and the bounds of the string literal are defined by the usual rules for the bounds of a string literal. End AARM Discussion.
Such a literal is said to be a user-defined literal.
Insert the following between the second and third sentences of 4.2.1(6/5) (in the Legality Rules section), making three separate paragraphs:
For a nonabstract type, the function directly specified for a user-defined literal aspect shall not be abstract.
For a tagged type with a partial view, a user-defined literal aspect shall not be directly specified on the full type.
If a nonabstract tagged type inherits any user-defined literal aspect, then each inherited aspect shall be directly specified as a nonabstract function for the type unless the inherited aspect denotes a nonabstract function and the type is a null extension.
Delete 4.2.1(7-8/5).
[This is the entire Dynamic Semantics section (it is now redundant).]
Modify 4.2.1(9/5):
It is a bounded error if the evaluation of a literal that has an expected type with a specified [Integer_Literal, Real_Literal, or String_Literal]{user-defined literal} aspect, propagates an exception. Either Program_Error or the exception propagated by the evaluation is raised at the point of use of the value of the literal. If it is recognized prior to run time that evaluation of such a literal will inevitably (if executed) result in such a bounded error, then this may be reported as an error prior to run time.
Modify AARM 4.2.1(9.a/5):
As always, an implementation may apply "as-if" optimizations (those that result in the same external effects in the absence of erroneous execution) to the function calls associated with user-defined literals. In particular, if the function associated with a [_Literal]{user-defined literal} aspect has a Global aspect that indicates no references to global variables, then a number of optimizations are available to the implementation:
Replace 6.3.1(22-22.a):
- each primary that is a literal in one has the same value as the
corresponding literal in the other.
AARM Ramification: The literals may be written differently.
with:
- each primary that is a literal in one is a user-defined literal
if and only if the corresponding literal in the other is also a user-defined literal. Furthermore, if neither are user-defined literals then they shall have the same values Redundant[, but they may have differing textual representations]; if both are user-defined literals then they shall have the same textual representation.
AARM Ramification: This rule applies to character_literals, so even though other rules would allow a rename of a character literal to conform to the literal, this rule prevents that.
!discussion
We've changed the definition of these aspects to be similar to the stream-oriented attributes. Thus, we've dropped the "nonoverridable" and "primitive subprogram" requirements, only requiring that the subprogram has the appropriate profile and is statically denoted.
This change also requires us to define this to be a dispatching operation (so that T'Class has literals if T has literals), and that requires ensuring that there is an appropriate function defined (similar to the way 3.9.3 requires functions of non-null extensions to be overridden).
We define a name for these attributes collectively so that we can easily name them in various rules.
We do have to require that the operations are not abstract for a nonabstract type. For untagged types, this is merely a convinience: any call on such a function is illegal, so the corresponding literal would be illegal, too. Detecting the error early seems better, however. In the case of a tagged type, we need to enforce rule on the type declaration so that it is not possible to dispatch to an abstract literal. Similarly, we need rules to ensure that any inherited functions are overridden unless the type is a null extension (for which the language will construct the needed function).
----
Because these are aspects, we don't get reemergence with formal derived types (the way that we might with primitive subprograms). That means that in this example,
procedure Proc is package Pkg is type T1 is (T1_Op, T2_Op) with Integer_Literal => F1; function F1 (S : String) return T1 is (T1_Op);
type T2 is new T1 with Integer_Literal => F2; function F2 (S : String) return T2 is (T2_Op); end Pkg;
generic type Formal_Derived is new T1; package G is end;
package body G is X : Formal_Derived := 123; end G;
package I is new G (T2); begin null; end;
the variable I.X is initialized with the value T2_Op, not T1_Op.]
----
The rule that does not allow hiding these aspects for tagged types is necessary to avoid a situation where a user-defined literal aspect needs to be overridden but that aspect is not visible. For instance:
package P is type T is tagged private; function Val (S : Wide_Wide_String) return T; private type T is tagged record ... with String_Literal => Val; end P;
with P; package P2 is type T2 is new P.T with record ...; overriding function Val (S : Wide_Wide_String) return T2; end P2;
Type T2 needs to override the String_Literal aspect, yet that aspect is not visible. (The overriding is necessary in case a dispatching literal is used with T'Class within the scope of the full type of T. We have to have a function to execute for T2 in that case.)
Note that this is required for nonoverridable aspects like Variable_Indexing. We don't make these aspects nonoverriddable since that does not work well for untagged types, and therefore we need our own rule to ensure this.
----
The new AARM Ramification for 6.3.1(22) is just noting that both 6.3.1(21/4) and 6.3.1(22/5) apply to character literals. In particular:
type Mixed is ('A', 'B', Sea); function Ocean return Mixed renames Sea; function Bad return Mixed renames 'B';
procedure P1 (A : Mixed := 'B'); procedure P2 (A : Mixed := Sea);
procedure P1 (A : Mixed := Bad); -- Illegal. procedure P2 (A : Mixed := Ocean); -- OK.
Even though 'B' and Bad denote the same declaration (thus satisfying 6.3.1(21/4)), they are not both literals, so 6.3.1(22/5) is not satisfied. Contrast to P2, where Sea and Ocean conform.
Argubly, it is a mistake to include character literals in 6.3.1(22/5) - as they denote declarations, not values, but it is insufficiently broken to change. (The situation above is likely very rare, and primary goal of the conformance rules is to allow exact matches with just a bit of wiggle room.)
!corrigendum 3.9.2(1/2)
Replace the paragraph:
The primitive subprograms of a tagged type, the subprograms declared by formal_abstract_subprogram_declarations, and the stream attributes of a specific tagged type that are available (see 13.13.2) at the end of the declaration list where the type is declared are called dispatching operations. A dispatching operation can be called using a statically determined controlling tag, in which case the body to be executed is determined at compile time. Alternatively, the controlling tag can be dynamically determined, in which case the call dispatches to a body that is determined at run time; such a call is termed a dispatching call. As explained below, the properties of the operands and the context of a particular call on a dispatching operation determine how the controlling tag is determined, and hence whether or not the call is a dispatching call. Run-time polymorphism is achieved when a dispatching operation is called by a dispatching call.
by:
The primitive subprograms of a tagged type, the subprograms declared by formal_abstract_subprogram_declarations, the subprograms identified by the user-defined literal aspects of a specific tagged type (see 4.2.1), and the stream attributes of a specific tagged type that are available (see 13.13.2) at the end of the declaration list where the type is declared are called dispatching operations. A dispatching operation can be called using a statically determined controlling tag, in which case the body to be executed is determined at compile time. Alternatively, the controlling tag can be dynamically determined, in which case the call dispatches to a body that is determined at run time; such a call is termed a dispatching call. As explained below, the properties of the operands and the context of a particular call on a dispatching operation determine how the controlling tag is determined, and hence whether or not the call is a dispatching call. Run-time polymorphism is achieved when a dispatching operation is called by a dispatching call.
!corrigendum 4.2.1(0)
Insert new clause:
** Force a conflict; the actual changes are in the conflict file. **
!corrigendum 6.3.1(22)
Replace the paragraph:
Each primary that is a literal in one has the same value as the corresponding literal in the other.
by:
each primary that is a literal in one is a user-defined literal if and only if the corresponding literal in the other is also a user-defined literal. Furthermore, if neither are user-defined literals then they shall have the same values, but they may have differing textual representations; if both are user-defined literals then they shall have the same textual representation.
!ASIS
No change here; the aspects already exist.
!ACATS test
ACATS B- and C-Tests will be needed to test that inheritance happens and that the various Legality Rules are enforced.
!appendix

From: Steve Baird
Sent: Thursday, August 15, 2019  7:49 PM

I have some questions question about user-defined literals.

#1)

The Integer_Literal, Real_Literal, and String_Literal aspects are
defined to be operational aspects.

13.1 says
   ... whether operational aspects are inherited by a derived type
   depends on each specific aspect; unless specified, an operational
   aspect is not inherited.

I saw no mention of inheritance or derived types in 4.2.1 (the section
on User-Defined Literals).

So these are not inherited? Is this what was intended?

There is no discussion of this question in the AI, so I'm wondering
whether this was an oversight.

Do we really want to reject

     package Big_Nums is
        type Big_Integer is private with Integer_Literal => ... ;
        ...
     end Big_Nums;

     with Big_Nums;
     package Client is
        type My_Int is new Big_Nums.Big_Integer;
        procedure Foo (X : My_Int := 1); -- legal literal ?
     end Client;
?

You can't even work around the problem because these are
nonoverridable aspects. Having nonoverridable non-inherited
aspects seems like a really bad idea - you can't inherit them
and you can't explicitly (re)specify them (unless you can
figure out how to write a confirming specification for a
non-inherited aspect),

One could imagine a rule that the specified subprogram for one of these
aspects has to be a primitive operation of the type; this would allow
the definition of an inherited aspect for a derived type to be the
corresponding primitive operation of the derived type. At least in the
case of a tagged type (and presumably for other types, just for
consistency) this notion of "corresponding" would then have to take
overriding into account.

Perhaps we want something along these lines.

#2)

Related to the question of derivation, do we really want to allow
these three aspects to be specified for an abstract type?

    type T1 is abstract tagged null record with Integer_Literal => ... ;

And do we want to allow an abstract function to be specified as
the value of one of these aspects?

    type T2 is private with Integer_Literal => Abstract_Func;
    function Abstract_Func (Lit_Image : String) return T2 is abstract;

At first glance, it might seem that other rules prevent these constructs
from causing any real problems. Specifically:
    If the result type of a function is abstract, then the function shall
    be abstract.
and
    A call on an abstract subprogram shall be a dispatching call;

But recall that the equivalence between a literal and a function
call is only dynamic semantics; it has nothing to do with any legality
rules. So the aforementioned rule about "a call on an abstract
subprogram" has no bearing on the legality of a use of a numeric
literal.

In any case, it seems like useless implementation complexity to allow
these useless constructs. As far as I can see, allowing these constructs
isn't doing the user any favors either.

#3)

Presumably the specified subprogram for one of these aspect
specifications can be the dereference of an access-to-subprogram
value?

Can it be a prefixed view of a subprogram?

I see no rule disallowing these cases, but I thought I'd
check to be sure.

Of course the restrictions discussed above in item #1 would
disallow them.

#4)

Is one of these user-defined literals an object or just a value?

More specifically, is the following example legal or not?

     type T1 is ... with Integer_Literal => ...;
     ...
     X : T1 renames T1'(123); -- legal?

I'd say it is not because, statically, 123 is not a function call
and literals are not on 3.3's "All of the following are objects"
list.

As mentioned earlier, the equivalence between literals and function
calls is strictly dynamic semantics.

On the other hand, something like

    type T2 is record
         Aliased_Component : aliased Some_Type;
         ...
      end record
      with Integer_Literal => ... ;
    ...
    procedure Foo (Ref : access Some_Type);
    ...
   begin
    Foo (T2'(123).Aliased_Component'Access); -- legal?
   end;

seems less clear. Is this legal?

I think we want these guys to be treated like function result objects
in the aforementioned 3.3 list. And besides, composite "values" seem odd
- for example, what does it mean to have an actual parameter in
a call which is a value, but not an object, of a by-reference type?

Interestingly, the 3.3 list does include "the result of evaluating
an aggregate" while 4.2 says "The evaluation of a string_literal ...
yields an array value ...". This seems like an area where the
equivalence between string_literals and array aggregates breaks
down even before we start talking about user-defined literals.

AI12-0270, which is about cleaning up these object/value issues,
is on hold. But just because we don't want to tackle the existing
problem doesn't mean we shouldn't avoid making the situation worse
with the addition of new features.

#5)

If one of these literals is not an object, then it doesn't have
a nominal subtype (recall that 3.3 says "At the place where a view of an 
object is defined, a nominal subtype is associated with the view").

I don't see that this causes any of the problems that
AI05-0006 was worried about because you cannot case on
a literal (because the expression of a case statement is
a complete context). And besides, a literal is not
a name (if that matters - AI05-0006 talks about ensuring
that every *name* has a well-defined nominal subtype).

On the other hand, "nominal type" is defined in terms of
"nominal subtype". However, having an undefined "nominal type"
doesn't seem to introduce any definitional problems.

So I don't think there are any problems here, but I thought I'd
raise the question.

===

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

From: Tucker Taft
Sent: Thursday, August 15, 2019  9:22 PM

...
> So these are not inherited? Is this what was intended?

Certainly not, in my view.
 
> There is no discussion of this question in the AI, so I'm wondering 
> whether this was an oversight.

Oversight for sure.

...
>    end Client;
> ?

Clearly these should be inherited.
 
> You can't even work around the problem because these are 
> nonoverridable aspects. Having nonoverridable non-inherited aspects 
> seems like a really bad idea - you can't inherit them and you can't 
> explicitly (re)specify them (unless you can figure out how to write a 
> confirming specification for a non-inherited aspect),

Yes, clearly an oversight.

...
> In any case, it seems like useless implementation complexity to allow 
> these useless constructs. As far as I can see, allowing these 
> constructs isn't doing the user any favors either.

But suppose you have an abstract type derived from a non-abstract type that 
has literals?  It seems we might want that to be legal. 

I would say you can't have a literal of an abstract type, but I see no 
particular harm in allowing an abstract type to have an aspect specifying 
it has user-defined literals.  Non-abstract types derived from the abstract 
type is where the literals could actually be used.

...
> Presumably the specified subprogram for one of these aspect 
> specifications can be the dereference of an access-to-subprogram 
> value?
> 
> Can it be a prefixed view of a subprogram?
> 
> I see no rule disallowing these cases, but I thought I'd check to be 
> sure.

Seems unimportant; if they create any problem I would make them illegal.

...
> I'd say it is not because, statically, 123 is not a function call and 
> literals are not on 3.3's "All of the following are objects"
> list.

Agreed. 

...
> seems less clear. Is this legal?

This looks really weird.  I don't particularly care whether or not it is 
legal.  Whatever is simpler.  I wouldn't go out of our way to make it legal, 
nor make it illegal.  Whatever falls out from the rules.

...
> AI12-0270, which is about cleaning up these object/value issues, is on 
> hold. But just because we don't want to tackle the existing problem 
> doesn't mean we shouldn't avoid making the situation worse with the 
> addition of new features.

Agreed.  Again, I don't think it matters much from the point of view of 
usability, so the simpler rule is probably the better rule.

...
> On the other hand, "nominal type" is defined in terms of "nominal 
> subtype". However, having an undefined "nominal type"
> doesn't seem to introduce any definitional problems.
> 
> So I don't think there are any problems here, but I thought I'd raise 
> the question.

There seems no harm in defining the nominal subtype/type of a user-defined 
literal, even if we don't have to for other reasons.

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

From: Steve Baird
Sent: Friday, August 16, 2019  3:07 AM

> If one of these literals is not an object, then it doesn't have
> a nominal subtype (recall that 3.3 says "At the place where a view of an 
> object is defined, a nominal subtype is associated with the view").
> 
> I don't see that this causes any of the problems that
> AI05-0006 was worried about because you cannot case on
> a literal (because the expression of a case statement is
> a complete context).

There is slightly more to this than I thought at first.

I implied that we can't case on a user-defined literal.

I think I was right about casing on an integer literal, as in

    case 123 is
      ...
    end case;

because that will always be ambiguous, but this might not be
true for other forms of literals.

The name resolution rules for case statements include
    The selecting_expression is expected to be of any discrete type.
so we can case on a literal other than an integer literal and it
is possible that resolution will be successful.

So I think it is possible to have case statements of the form

     case 123.45 is
        ...
     end case;

or

    case "dog" is
      ...
    end case;

where the type of the user-defined literal is an enumeration type
(enumeration types are discrete but not numeric).

But since a literal is not a name, the case statement rules
don't care about its nominal subtype so it is ok that
nominal subtype is undefined in these cases.

We don't want this example to be legal

     procedure Foo1
        type Enum1 is (Aa, Bb, Cc, Dd, Ee);
        type Enum2 is new Enum1 range Bb .. Dd with Real_Literal => R_L;
        function R_L (Lit : String) return Enum2'Base is (Ee);
     begin
        case 1.0 is
            when Enum2 =>
               null;
        end case;
     end;

but I think that falls out from the current rules.

====

> Clearly these should be inherited.

I agree, but it needs to be stated explicitly how this works
in the tagged case (for the same reason that we have the 3.9.3
rules about the "if a type other than a nonabstract null extension 
inherits a function with a controlling result" case).

We don't want to allow something like

     package Pkg is
        type T1 is tagged null record
          with Integer_Literal => Nested.Not_A_Primitive;

        package Nested is
          function Not_A_Primitive (Lit : String) return T1 is
            (null record);
        end Nested;

        type T2 is new T1 with record Field : Float; end record;

        X2 : T2 := 123;
     end Pkg;

and even if we delete the inner package so that
the function becomes a primitive, we still need some rules to
define how the inheritance works.

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

From: Randy Brukardt
Sent: Friday, August 16, 2019  5:51 PM

> and even if we delete the inner package so that the function becomes a 
> primitive, we still need some rules to define how the inheritance 
> works.

Actually, we need rules to state how it works in any case, 'cause untagged 
routines don't magically work without rules, either. (Recall the rules about
type converting the arguments given in 3.4.) I would suggest just requiring 
the routine to be primitive for any type, as that way the routine will always
be inherited and thus we wouldn't need to define any rules for what that 
means. It's easy enough to define a primitive expression function in the 
unusual case where someone needs to declare a non-primitive function as the 
user-defined literal routine, so the added expressivity by allowing any 
routine in the untagged case doesn't seem worth the complication.

I presume that you are providing a fix-up AI with rules for all of these 
issues, right, complete with questions/discussion??? :-)

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

From: Steve Baird
Sent: Friday, August 16, 2019  6:20 PM

> I presume that you are providing a fix-up AI with rules for all of 
> these issues, right, complete with questions/discussion???

Sure, I'll take that action item.

Like you, I'm leaning toward the general idea that the specified function
has to be a primitive operation of the type (I like your approach of requiring 
this even in the untagged case). In the untagged case presumably you get 
reemergence - overriding an inherited subprogram doesn't change the behavior 
of evaluating a literal.

In the tagged case, I see the dynamic semantics of evaluating a literal whose 
type has an inherited user-defined-literal aspect as being equivalent to those
of a dispatching call to the function named in the original aspect 
specification (having the descendant type's tag as the controlling tag value) 
followed by a conversion to the descendant type. So in that case, overriding 
an inherited subprogram can change the behavior of evaluating a literal.

I haven't thought about untagged views of tagged types and descendants 
thereof, but I don't think there are big problems there.

Obviously wording is needed for all of this (that was your point).

Presumably the 13.1.1 rule that
   If a type inherits a nonoverridable aspect from multiple ancestors,
   the value of the aspect inherited from any given ancestor shall be
   confirming of the values inherited from all other ancestors.

means that the following example is legal

     package Pkg is
       type Ifc1 is Interface with Integer_Literal => I_L;
       function I_L (Lit : String) return Ifc1 is abstract;

       type Ifc2 is Interface with Integer_Literal => I_L;
       function I_L (Lit : String) return Ifc2 is abstract;

       type Concrete is new Ifc1 and Ifc2 with null record
         with Integer_Literal => I_L;
       function I_L (Lit : String) return Concrete;
     end Pkg;

and, furthermore, the aspect specification for type Concrete is redundant 
and could be omitted without any effect.

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

From: Steve Baird
Sent: Tuesday, September 10, 2019  7:31 PM

The attached is a new AI, aimed at addressing some of the problems with 
user-defined literals that were identified in my ARG mail message of 
Aug 15 2019 and in subsequent discussions.

[This is version /01 of the AI, with some missing parts added. - Editor.]

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

From: Randy Brukardt
Sent: Tuesday, September 24, 2019  10:33 PM

This AI is not ready for prime-time, sadly. You didn't change it at all (at
least I can't see any significant changes) from the version we discussed
privately and was considered the wrong solution.

(1) Editorial: A !proposal section should immediately follow the !problem
section. (I stuck in "See summary."). The !discussion goes after the
wording. I realize you put this where you did because the entire AI is not
really finished given that you ignored the advice Tucker and I gave you
privately -- but this is useless for the ARG -- finish it first.

(2) Abandoning 100% of the existing wording means a complete restart on the
wording. Most likely, all of the wording changes in 4.2 and elsewhere will
also have to be reworded (which you neither did nor made any discussion
about having checked). All of the existing wording was written in terms of a
type having a specified aspect, and that isn't appropriate when an aspect is
inherited.

(3) Constant_Indexing is only defined for tagged types, and thus the
inheritance rules are built around that. Integer_Literal et. al. have to
work for untagged types, and inheritance of those is squirrely at best.

(4) Similarly, "Nonoverridable" is only well-defined for tagged types.

(5) The "stream-attribute" model seems a better fit for these aspects.
There's no reason to make this overly complicated -- indeed, if it gets much
more complicated, I suspect most of the ARG would simply vote to remove it
(only a handful of people really supported it in the first place -- it has
to be simple). I could even make an argument that the original
no-inheritance model is best for untagged types.

A few specific comments.

>... the "default" inheritance rule described in 13.1(15.2/2) doesn't work.

Right, but you seem to be drawing the wrong conclusion from that. One
*always* has to specify how inheritance works for type extensions as no
default rule could possibly make sense. What happens to the extension
components always has to be defined.

>They feel (I hope I am stating their position correctly) that following
>the "Constant_Indexing model", where the value of the aspect is not a
>subprogram but rather the name of a subprogram, may be unnecessarily
complex
>in the case where the aspect refers to a single subprogram rather than
>to (potentially) a set of subprograms (as is the case with the
>Constant_Indexing aspect). They would prefer something more similar
>to the way that inheritance of streaming attributes is handled. This would
>presumably involve mandatory overriding in the case of a type extension.

At a minimum, we need to try writing up the AI that way to see if it does
simplify the presentation. I personally think the stream attribute model
makes far more sense for these aspects, but in the absence of trying it, we
cannot really know.

>Tuck makes the good point that we need to agree on a meta-rule to decide
>when to use which model so that we don't end up making this decision
>arbitrarily on an aspect-by-aspect basis as new aspects arise.

I proposed a meta-rule in the private e-mail as a starting point for
discussion:

(1) If any type is allowed, and the profile is fully specified with only a
single match allowed, then use the streaming model.
(2) If only tagged types are involved, and if the profile is only partially
specified, and especially if a family is desired, then use "nonoverriding"
and names.
(3) If only tagged types are involved, and the profile is fully specified,
use whichever model makes the most sense. ("Nonoverriding" might work better
for interfaces, not sure.)
(4) In any other case (mainly any type with a partially specified family
profile), please don't do that. ;-)

Note that the only other sensible meta-rule is "Never use the stream
attribute model", but that will require extending the
"Constant_Indexing/nonoverridable" model to support untagged types. (Which I
suspect will be a morass, given that inheritance/overriding of untagged
types has almost no rules, especially about parameter modes and defaults.)

To hack an example from your private mail to show one part of the problem:

      type T1 is (T1_Op, T2_Op) with Integer_Literal => I_L;

      function I_L (S : String) return T1 is (T1_Op); -- primitive

      type T2 is new T1;  

      overriding
      function I_L (S : out String) return T2 is (T2_Op);

The overriding function is a legal overriding for an untagged type. But it
is not a legal Integer_Literal aspect. The Constant_Indexing/nonoverridable
model doesn't worry about such cases 'cause they can't happen for tagged
types. Adding a pile of such rules sounds messy and expensive for
implementations.

>Randy questions whether these new aspects need to be overridable. I think
>we at least want the property (which is a consequence of being overridable)
>that all views of a single type agree with respect to the new aspects.

This is a basic property of aspects (that they are never view-specific); the
question is how that is enforced, not whether it is true or not. As
previously noted, "nonoverridable" prevents certain specifications of
aspects; I don't see any reason to do that here (certainly not for untagged
types). The stream attribute model uses re-specification to handle
redefinition, otherwise the original routine is inherited unmodified.

Note that the stream attribute model essentially makes the stream aspects
primitive operations of the type (and there is no relationship to any
inherited subprograms); that seems to make more sense in this case.

...
>[TBD: the corresponding uses of function_name instead of direct_name
>in 4.1.6 probably should be changed to match the above; we don't want to
allow
>   package Foo is
>      ...
>      type T is ... with Constant_Indexing => Foo.Bar;
>      function Bar ... ;
>      ...
>   end Foo;
>, right?]

Why? What's the harm? The requirement for a "primitive function" eliminates
any dynamic names (dereferences are never primitives), so we're only talking
about expanded names. Yes, it's a bit redundant, but I don't see any problem
with it.

...
>A user-defined literal is illegal if the equivalent function call is
illegal.
>
>[AARM note: For example, this implies that if the equivalent function call
>is a call to an abstract subprogram then the equivalent function call
>shall be a dispatching call.]

I note that this particular example is not possible in the stream-attribute
model; specified subprograms cannot be abstract. Not sure if that is
significant.

>A user-defined integer literal of a type T is illegal if the type T
>does not have exactly one visible primitive function having the name
>specified in T's (explicit or inherited) Integer_Literal aspect
specification,
>a result type of T, one parameter of type String, and no other parameters.
>[AARM note: If exactly one such primitive function exists then that is the
>function that is called when the literal is evaluated.]

This is horrible. This is always known when type is defined (since we're
only talking about primitive operations) [at least at the end of the unit in
which it is defined], it needs to be enforced there. That should be the case
even if we end up using the Constant_Indexing model (which clearly is not a
good match given the need for this bizarre rule). Also note that you seem to
be using this to fix up the deficiencies of "nonoverridable" for untagged
types, but that is a terrible approach since the next guy to use
"constant_indexing" on all types is highly unlikely to remember this nuance.

----

Replace 6.3.1(22-22.a):

>   - each primary that is a literal in one is a user-defined literal
>     if and only if the corresponding literal in the other is also a
>     user-defined literal. Furthermore, if neither are user-defined
literals
>     then they shall have the same values [redundant , but they may have
>     differing textual representations]; if both are user-defined literals
then
>     they shall have the same textual representation.

While I agree with this semantics, the term "textual representation" is
undefined in the RM (the only place it appears is twice in the current 4.2.1
-- and that isn't acceptable either). Either we have to define what this
means somewhere in Clause 2 (OK, Chapter 2 to pretty much anyone not using
current ISO terminology), or come up with an alternative. 

In particular, "representation" has a formal meaning in Ada (see 13.1), and
this use is very different. 2.2 using the term "text of a program", but
lexical elements are made up of a "sequence of characters". (Thus the two
possible wordings given above.) I note that equivalence of identifiers are
described in terms of a "sequence of characters", so probably that would be
the best.

So either say "the sequence of characters of the literal lexical elements is
the same", or define "textual representation of a lexical element" in 2.2 to
mean "the sequence of characters of the lexical element". (Since the latter
doesn't seem to shorten anything much, I'd just use the longer phrase.)

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

From: Tucker Taft
Sent: Thursday, September 26, 2019  3:57 PM

It seems like Steve ran out of time before his vacation, or simply missed one 
of your emails, Randy.  I agree that your "meta rule" is a good start, and it 
would be nice to discuss it explicitly in the ARG meeting, hopefully with 
some examples (since in the abstract it can be pretty hard to decide!).

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

Editor's Note (January 16th, 2020)

The proposed wording had "each inherited aspect shall be overridden". But
"shall be overridden" is not defined for aspects, we should have said
"shall be directly specified".

We want these aspects to be dispatching for tagged types, so that they are
available for classwide subtypes. That requires specific wording in 3.9.2(1).

To keep that wording from being unwieldy, we need to name these aspects. After
consulting with Tucker Taft and Steve Baird, "user-defined literal aspects"
was chosen. We then used this term rather than other vague descriptions or
lists of attributes - this makes the wording of 4.2.1 much clearer (and more
resistant to future problems should we decide to add Character_Literal or
Null_Literal in the future).

We considered this part of the editorial review of this AI.

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

From: Randy Brukardt
Sent: Thursday, January 23, 2020  11:40 PM

I made the mistake of thinking about AI12-0342-1 rather than mechanically 
adding the wording to the draft RM, and thus I found a number of issues that 
needed fixing in the AI. All of these have been reviewed by Steve and Tucker, 
and they agree with me that none of these rise to the level of something that 
requires reopening the AI.

So, if anyone of you want to discuss these changes at a meeting, please speak 
up and we'll put the AI back on the agenda for the next meeting. Otherwise, we
will process this as my editorial review of the AI and we won't spend limited 
meeting time on it again.

I've posted the updated AI on the website (in the version control only) if you
want to look at the detailed changes and/or diffs.

                             Randy Brukardt, ARG Editor.


[1] The proposed wording had "each inherited aspect shall be overridden". But
"shall be overridden" is not defined for aspects, we should have said
"shall be directly specified".

[2] We want these aspects to be dispatching for tagged types, so that they are
available for classwide subtypes. That requires specific wording in 3.9.2(1).
(These are modeled after stream-oriented attributes, and *those* have specific
wording in 3.9.2(1)).

[3] To keep that wording from being unwieldy, we need to name these aspects. After
consulting with Tucker Taft and Steve Baird, "user-defined literal aspects"
was chosen. We then used this term in all of the wording of 4.2.1 rather than other 
vague descriptions or lists of attributes - this makes the wording of 4.2.1 much 
clearer (and more resistant to future problems should we decide to add Character_Literal or
Null_Literal in the future). This does change a number of paragraphs and AARM notes
not otherwise changed.

[4] The added Legality Rule needs to be enforced in all of a generic specification
and rechecked in an instance in case the type extension has a parent type that
is a generic formal type. In that case, we don't necessarily know whether 
something is inherited until the instance is processed. Moreover, allowing
such an extension would be to have objects created without all of the 
components of the extension, which clearly cannot be allowed. Note that
deriving a type from a tagged formal type is not allowed in a generic body
(specifically because inheritance rules such as abstract operation rules
cannot be enforced).

This was handled with the editorial changes of moving the generic boilerplate
sentence from 4.2.1(6/5) to its own paragraph at the end of the Legality Rules
section and inserting the new rule in between.

[5] We want to prevent a user-defined literal aspect being directly specified
as an abstract function for a nonabstract type. (We want to allow it on abstract 
types so that interfaces and the like can define literals - if the literal is an
important part of the abstraction, it would be bad to not be able to define it.)

For untagged types, this is just a convenience: any literal would be illegal by
the static semantics equivalence. But there's little point in allowing a 
declaration for which any use would be illegal. For tagged types, however, it
would be possible to dispatch to the literal function from some ancestor, and we 
surely cannot allow executing an abstract function.

To handle this, we add the following rule:

   For a nonabstract type, the function directly specified for a user-defined 
   literal aspect shall not be abstract.

[6] We have a similar problem when inheriting abstract functions (if we allow that
one could call an abstract function via a dispatching call). Thus, we change the
originally proposed Legality Rule to:

   If a nonabstract tagged type inherits any user-defined literal aspect, then 
   each inherited aspect shall be directly specified as a nonabstract function 
   for the type unless the inherited aspect denotes a nonabstract function and 
   the type is a null extension.

[7] Enforcing the above rule could be a problem if there are hidden specifications
of a user-defined literal aspect. For example:

    package P is
       type T is tagged private;
       function Val (S : Wide_Wide_String) return T;
    private
       type T is tagged record ...
           with String_Literal => Val;
    end P;

    with P;
    package P2 is
       type T2 is new P.T with record ...;
       overriding
       function Val (S : Wide_Wide_String) return T2;
    end P2;

Type T2 needs to override the String_Literal aspect, yet that aspect is not
visible. (The overriding is necessary in case a dispatching literal is used
with T'Class within the scope of the full type of T. We have to have a function
to execute for T2 in that case.)

Hidden literals seem contrary to the purpose of these aspects (which is to define
literals for private types). Moreover, we have a similar rule for nonoverridable
aspects like Variable_Indexing and Implicit_Dereference.

[8] The new 6.3.1(22) (and the old one, as well) apply to character_literals. But
6.3.1(21/4) also applies to character_literals. This looks like a mistake, but it
isn't worth fixing this as conformance does not need to be very smart. As such, I
added an AARM note after 6.3.1(22):

  AARM Ramification: This rule applies to character_literals, so even though 
  other rules would allow a rename of a character literal to conform to the 
  literal, this rule prevents that.

This note is talking about a case like:

    type Mixed is ('A', 'B', Sea);
    function Ocean return Mixed renames Sea;
    function Bad return Mixed renames 'B';

    procedure P1 (A : Mixed := 'B');
    procedure P2 (A : Mixed := Sea);

    procedure P1 (A : Mixed := Bad);   -- Illegal.
    procedure P2 (A : Mixed := Ocean); -- OK.

Even though 'B' and Bad denote the same declaration (thus satisfying
6.3.1(21/4)), they are not both literals, so 6.3.1(22/5) is not satisfied.
Contrast that to P2, where Sea and Ocean conform.

[9] I put quite a bit of the above into the !discussion of the AI.

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

From the AARM review of Tucker Taft (October 2020)

We introduce the aspects in paragraph (2/5) with:

2/5: The following type-related operational aspects 
(collectively known as user-defined literal aspects) may be 
specified for any type T:

It feels like the "for any type T" is somewhat misleading, in 
that later we limit these aspects to non-numeric, or 
non-string types.  Perhaps simply say "for a type T:" to 
finesse the issue.

[Editor's response:]
Technically, of course, a Legality Rule that says you can't *specify* an 
aspect for some type is not the same thing as saying that the aspect is 
*defined* for a type. Of course, in this case where the default value of the 
aspect is to not have a literal function, the difference is somewhat academic.

However, "any type" is the wording used for attributes, not for aspects. 
Aspects generally just say "for a <blah>". So your suggestion is less a 
finesse and more just the way it ought to be done for consistency.

> We have the following AARM note:
> 
> 5.b/5: Ramification: {AI12-0342-1} The following example is 
> legal because the preceding rules are Name Resolution Rules 
> (see 13.1.1):
> 
> But the rules are listed in the Static Semantics section, so 
> this is confusing, even with the "see 13.1.1" which 
> presumably clarifies (?).  Perhaps we could put this all 
> under the Name Resolution section title. 

That would be inconsistent with all of the other aspect definitions, and also 
potentially would be wrong. I think the problem here is the note, as it's an 
oversimplification. 13.1.1(8/3) says that for an aspect that denotes a 
subprogram, the aspect definition is a name and the expected profile for the 
name is the one defined for the aspect. So these rules define the kind of 
aspect (subprogram) and the profiles defined for the aspect. That's Static 
Semantics. And then the Name Resolution Rule in 13.1.1 uses those definitions 
for resolution of the aspect_definition. So the note should say something like:

  5.b/5: Ramification: The following example is legal because the resolution 
  of an aspect_definition for an aspect that is defined to be a subprogram is
  based on the profile required for that aspect (see 13.1.1):


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

From: Tucker Taft
Sent: Wednesday, July 14, 2021  7:18 AM

There is a missing word in 4.2.1(7/5):

When a numeric literal is interpreted as a value of a non-numeric type T or a 
string_literal is interpreted {as} a value of a type T that is not a string 
type (see 4.2), it is equivalent to a call to the subprogram denoted by the 
corresponding aspect of T: ...

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

From: Randy Brukardt
Sent: Wednesday, July 14, 2021  10:45 PM

It's too late to fix this in the submission copy (and it's been wrong since 
at least January 2020, so the importance is low), but as we're usually able
to fix typos at any point, it's likely that we'll have some point when it 
can be fixed. And I fixed it in my local source files, so the next time the
documents are generated (at least for a printed version) it will be fixed.

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

Questions? Ask the ACAA Technical Agent