Version 1.1 of ai22s/ai22-0036-1.txt

Unformatted version of ai22s/ai22-0036-1.txt version 1.1
Other versions for file ai22s/ai22-0036-1.txt

!standard 3.5(56.3/3)          22-01-26 AI22-0036-1/01
!class binding interpretation 22-01-26
!status work item 22-01-26
!status received 21-04-28
!priority Low
!difficulty Easy
!qualifier Omission
!subject
!summary
[Editor's note: The purpose of this AI is to determine if this is a Binding Interpretation (applying to Ada 2012 and Ada 2022) or whether it should be an Amendment (only applying to the next version of the language). Once determined, it will be assigned to someone to complete or shepard through the new UCI process, as appropriate.]
Attributes 'First, 'Last, and 'Val are specially recognized in the expression of a Default_Value aspect.
!question
I wanted to create a Character type for which the default value is the NUL character, (Ada.Characters.Latin_1.Nul).
However, there does not appear to be any legal way to do it. One needs some sort of conversion of the Nul value (since it is not an enumeration literal of the type, so it is not inherited), but all such conversions are illegal.
For instance:
type Char is new Character with Default_Value => Char (Ada.Characters.Latin_1.Nul);
This is illegal because Char is a constant object (the current instance of type Char), and thus cannot be used as the prefix of a type conversion.
Should some way be available? (Yes.)
!recommendation
(See Summary.)
!wording
*** TBD ***
!discussion
We previously decided in AI12-0367-1 to only add a narrow rule allowing enumeration literals. We considered other cases at that time, and did not think they were important enough. We did not consider this example at that time, and we probably would have had a different opinion if we had done so. The best solution to this problem is to allow at least T'Val, as it allows arbitrary position numbers of the type. The use of T'First and T'Last also seem natural (we know the values without freezing, as the bounds of any scalar type are required to be static).
However, inside of an aspect specification, the name of the type refers to the current instance of the type. The usual scalar attributes are not defined on an object, and even if they were, referencing the current instance would cause circular freezing.
In order to avoid both of these problems, we need to specially define the use of these attributes in the expression of a Default_Value aspect specification.
Note that we don't want to allow any scalar attribute. Many attributes would necessarily require the type to be frozen first (think 'Size or 'Enum_Rep), which would cause circularities. Similarly, We only define these for the associated type; allowing them on a subtype of the type could cause circular freezing issues for the same reason (the bounds of the subtype could involve an attribute that itself would require freezing of the base type, which is circular).
[Editor's opinion: This seems to me to be quite a bit of mechanism for a problem that only occurs for the type Character, Wide_Character, and Wide_Wide_Character (as these are the only enumeration types that do not have a nameable enumeration literals for every position). As such, it seems to make more sense as an Amendment; it can then be implemented if there is sufficient demand for it (it will be interesting to see if others run into this problem).]
!ACATS test
An ACATS C-Test is needed to check that these attributes are allowed for a Default_Value aspect specification.
!appendix

From: Brad Moore [privately]
Sent: Saturday, December 4, 2021  11:01 PM

I stumbled onto a problem for which I thought would be easy to do in Ada, but 
appears to be very difficult if not, impossible.

I wanted to create a Character type for which the default value is the NUL 
character, (Ada.Characters.Latin_1.Nul)

The closest I got was;

type Char is new Character  
   with Default_Value => Char (Ada.Characters.Latin_1.Nul);

But that gives me a compile error in GNAT. 

 error: aspect specification causes premature freezing of "Char", 

which makes sense to me.

If it was a graphic character, such as space, then this would be easy.

type Char is new Character with Default_Value => ' ';

But since Nul isn't a graphic character, I cant specify it in a literal.

I even tried using the Integer_Literal aspect, to get the value 0 to to be 
used, using a fairly complex expression using 'Val and 'Pos, but that also 
gave me a compile error stating that the value 0 (for Default_Value), had 
to be a static expression, probably because of all the machinations to go 
from 0 to a Char value. 

Do you agree this should be an AI? And if so, should an AI be created, or 
should we just not bring this up right now, while we are standardizing Ada 
2022, and remember to bring it up farther down the road, when we are ready 
to look at Ada 2022 issues?

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

From: Randy Brukardt [privately]
Sent: Sunday, December 5, 2021  6:20 PM

When we discussed this originally (in AI12-0367-1), we considered various
rules. But ultimately a narrow exeception solely for enumeration literals
in a Default_Value was proposed (as there already was a similar exception
for enumeration representation clauses). We knew there were things that 
would be hard to do (they're called out in the !discussion), but I'm not
sure that anyone thought of this particular case (which is only a problem
because some of the positions in Character do not have nameable enumeration
literals).

I could see allowing attributes of the type (which would allow 'Val and 
'First, either of which could solve this problem), but that has semantic
issues (you would be allowing static expressions that you can't safely 
evaluate as the type isn't frozen). A compiler would probably need some 
special case code to deal with such cases, which is ugly when only a handful
of types are involved.

It may make more sense to leave this impossible as the fix is worse than the 
problem. (Note that one can define a string type with a default, the problem 
only occurs for Character, Wide_Character, and Wide_Wide_Character.)

I suppose we need an AI to discuss it, though.

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

From: Tucker Taft [privately]
Sent: Sunday, December 5, 2021  9:45 PM

I could see allowing the use of 'Val, 'Pos, 'First, and 'Last in the 
Default_Value aspect.  These would be quite natural to use in such an aspect,
even for a numeric type.  We are trying to identify a particular value, which
really has nothing to do with its representation.

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

From: Randy Brukardt [privately]
Sent: Monday, December 6, 2021  9:58 PM

We'd have to be careful with 'First and 'Last, as they could be any arbitrary 
static expression (especially if a subtype is involved). 'Enum_Rep and 
'Enum_Val could be a problem.
 
A static expression freezes in all contexts other than an aspect_spec by 
13.14(8/4). So that means that you can't allow using 'First or 'Last in 
Default_Value unless it is of the type itself and there is no constraint for
the type. (Anything else would have frozen the type before the aspect specs 
were defined - that would be the circular freezing that the freezing rule is
intended to prevent.) Seems like an unnecessary complication, since the value
involved is directly in the associated declaration.
 
I'd probably limit any additional rule to T'Val in the definition of T, simply 
to avoid any extra complications.
 
I'm thinking of a case like:
 
      type T is (A, B, C, D, E) with Default_Value => S'First;
      subtype S is T range T'Enum_Val(1) .. T'Enum_Val(4); -- (1)
 
The subtype freezes T at (1), but that needs the value of S'First, which needs 
the frozen rep. values of T. The attributes at (1) meet the requirements of 
4.9(7) to be static (if they didn't, T'Val(1) would not be static, which would 
be nonsense). One could have an enumeration rep. clause for T to make this more
interesting, for instance:
     for T use (A => 1, B => 2, C => 4, D => 8, E => 16);
 
The original freezing rule exists to prevent this sort of circularity 
(possible because resolution isn't done until the freezing point for aspect
specs).
 
****************************************************************

From: Tucker Taft [privately]
Sent: Tuesday, December 7, 2021  8:11 AM

I presumed we were only talking about special handling for 'First, 'Last,
'Val, and 'Pos where the prefix is the current instance of a scalar type.
With any other prefix, they would be treated like normal uses of the
attribute.  Normally a prefix that is a current instance would be interpreted
as a value/object, so there needs to be some special handling in any case, so
allowing the use of these attributes, which aren't even defined for scalar 
objects, without freezing seems reasonable.

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

From: Stephen Baird [privately]
Sent: Tuesday, December 7, 2021  9:02 AM

This probably isn't relevant, but I'll note that Brad's original attempt
    > type Char is new Character  with Default_Value => Char
    > (Ada.Characters.Latin_1.Nul)
also runs afoul of the current instance rule (8.6(17)).

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

From: Tucker Taft [privately]
Sent: Tuesday, December 7, 2021  9:17 AM

I would say it is highly relevant.  Almost any attempt to define a 
Default_Value "programmatically" is going to run afoul of the current
instance rule.  'First or 'Last seem by far the most likely to be used
in such an attempt, with 'Val(NN) to be the next most likely. 

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

From: Brad Moore [privately]
Sent: Tuesday, December 7, 2021  9:29 PM

Yes, I was assuming I'd need to do a cast to get to the new type, so not sure
I would have ordinarily tried to use 'First or 'Var without doing the cast.
But I think if the compiler could give a helpful suggestion to use an allowed 
attribute, that would have worked, if we decided to allow this.

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

From: Randy Brukardt [privately]
Sent: Wednesday, December 8, 2021  12:29 AM

One can work around the current instance issue with a subtype, as I showed 
yesterday, and indeed all of the examples of the need for the freezing rule
in the first place involved such subtypes. But I suppose for practical
reasons, one would usually use the type itself. Of course, this makes this
a fairly complex suggestion -- one has special case rules for a handful of
attributes in a single context not just for freezing but even for the
interpretation of the meaning. I have to wonder if such a change is worth it,
given that there is only a true problem for derivatives of types Character,
Wide_Character, and Wide_Wide_Character - something I'd discourage anyway.

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

From: Tucker Taft [privately]
Sent: Wednesday, December 8, 2021  9:22 AM

I guess I would claim that an aspect spec such as "Default_Value => T'First" 
might be quite common even for a numeric type, and forcing the user to
explicitly use the low bound for the type instead would actually obfuscate
the intent.  So I don't see this as a corner case.  I would agree T'Val(0) is
more of a corner case, but if we allow T'First then allowing T'Val seems easy
enough.  Having to declare a subtype for this purpose is truly ugly.

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

Questions? Ask the ACAA Technical Agent