Version 1.4 of acs/ac-00215.txt

Unformatted version of acs/ac-00215.txt version 1.4
Other versions for file acs/ac-00215.txt

!standard 4.3.1(11)          11-03-31 AC95-00215/01
!class confirmation 11-03-31
!status received no action 11-03-31
!status received 11-03-09
!subject Positional record aggregates and record extensions
!summary
!appendix

!topic Positional record aggregates and record extensions
!reference 4.3.1(11)
!from Adam Beneschan 11-03-09
!discussion

Randy wrote:

> The ARG adopted the following resolution at the end of the recent meeting:
>
> "Thanks to Adam Beneschan for providing problems whose complexity is in
> inverse proportion to their importance."

In an effort to continue providing this valuable service, I offer the
following:

4.3.1(11) says that when a record aggregate is in positional notation,
the expected type for a record_component_association is the type of
the component in the corresponding relative position (in the
declarative region of the type).

What is the definition of "corresponding relative position"; in
particular, how is this defined when the type is a record extension?

If "corresponding relative position" refers to where a component is
defined in the source (relative to other relevant components), what
does it mean in the aggregates for these two types?

    package Pack1 is

        type Type1 is tagged record
            Comp1 : Integer;
        end record;
        type Type2 (Disc1 : Integer) is new Type1 with record
            Comp2 : Integer;
        end record;

        type Type3 is tagged private;
        type Type4 (Disc2 : Integer) is new Type3 with private;

        procedure Foo;
    private
        type Type3 is tagged record
            Comp3 : Integer;
        end record;
        type Type4 (Disc2 : Integer) is new Type3 with record
            Comp4 : Integer;
        end record;
    end Pack1;

    package body Pack1 is
        procedure Foo is
            X1 : Type2 := (1, 2, 3);   -- Comp1=1, Disc1=2, Comp2=3?
            X2 : Type4 := (4, 5, 6);   -- Comp3=4, Disc2=5, Comp4=6?
                                       -- If not, what?
        begin
            ...
        end Foo;
    end Pack1;

Also, I noticed that the NOTE in 4.3.1(21) was copied almost verbatim
from RM83; but it doesn't make sense when record extensions with new
known discriminant parts are involved, when the parent type has
components that need to be in the aggregate.

P.S. If this really does cause any ARG members' heads to explode,
could someone please post a video?  :) :) :)

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

From: Randy Brukardt
Sent: Wednesday, March  9, 2011  9:22 PM

> > "Thanks to Adam Beneschan for providing problems whose complexity is
> > in inverse proportion to their importance."
>
> In an effort to continue providing this valuable service,...

I think you might have missed the point. ;-)

> ... I offer the following:
>
> 4.3.1(11) says that when a record aggregate is in positional notation,
> the expected type for a record_component_association is the type of
> the component in the corresponding relative position (in the
> declarative region of the type).
>
> What is the definition of "corresponding relative position"; in
> particular, how is this defined when the type is a record extension?

Nice. Another aggregate problem. The resolution came mostly from frustration
with AI05-0115-1, which has now pretty much stymied the entire ARG. Part of the
problem is that the actual Ada rules are pretty silly (not really what you would
want), but it would be incompatible to fix them. Thus we get into major knots
trying to fix rules no one really wants. (Tucker seems to think that there is an
entire area that isn't defined well enough, but if that was true, I would have
thought you would have found it by now. ;-)

> If "corresponding relative position" refers to where a component is
> defined in the source (relative to other relevant components), what
> does it mean in the aggregates for these two types?
>
>     package Pack1 is
>
>         type Type1 is tagged record
>             Comp1 : Integer;
>         end record;
>         type Type2 (Disc1 : Integer) is new Type1 with record
>             Comp2 : Integer;
>         end record;
>
>         type Type3 is tagged private;
>         type Type4 (Disc2 : Integer) is new Type3 with private;
>
>         procedure Foo;
>     private
>         type Type3 is tagged record
>             Comp3 : Integer;
>         end record;
>         type Type4 (Disc2 : Integer) is new Type3 with record
>             Comp4 : Integer;
>         end record;
>     end Pack1;
>
>     package body Pack1 is
>         procedure Foo is
>             X1 : Type2 := (1, 2, 3);   -- Comp1=1, Disc1=2, Comp2=3?
>             X2 : Type4 := (4, 5, 6);   -- Comp3=4, Disc2=5, Comp4=6?
>                                        -- If not, what?
>         begin
>             ...
>         end Foo;
>     end Pack1;

I think this is right (that's the order that the components were declared in the
declarative region of the type). Not particularly sure, though. There is a good
reason that almost all Ada style guides do not allow positional record
aggregates. :-)

> Also, I noticed that the NOTE in 4.3.1(21) was copied almost verbatim
> from RM83; but it doesn't make sense when record extensions with new
> known discriminant parts are involved, when the parent type has
> components that need to be in the aggregate.

Looks like that note is complete garbage. It doesn't seem to be true of any
record extension with discriminants. (Of course, extensions with discriminants
are already pretty silly...)

> P.S. If this really does cause any ARG members' heads to explode,
> could someone please post a video?  :) :) :)

I don't have a camera here today...so I'll resist trying to resolve this.
:-)

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

From: Christoph Grein
Sent: Wednesday, March  9, 2011  11:55 PM

>     package body Pack1 is
>         procedure Foo is
>             X1 : Type2 := (1, 2, 3);   -- Comp1=1, Disc1=2, Comp2=3?
Hu, I'd have thought                        Disc1=1, Comp1=2, Comp2=3!
>             X2 : Type4 := (4, 5, 6);   -- Comp3=4, Disc2=5, Comp4=6?
                                            Disc2=4, Comp3=5, Comp4=6!

This is the sequence in which they appear in the declarations of Type2 and Type4
(I'd have thought). But this is obviously not what the RM defines in 8.1 as
declarative region. I've always thought discriminants always come first. Ugh!

This is my intuitive feeling. I do not know about other's intuition. So this is
a place where the RM is against (my) intuition.

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

From: Adam Beneschan
Sent: Thursday, March 10, 2011  11:48 AM

My understanding has been that you take the components (including the
discriminants) of the ultimate ancestor type, followed by the components of the
type derived from that, and so on, until you get to the type of the aggregate,
and then select the needed components keeping the same order.  So a component of
a parent type would come before a discriminant of a child type.

But it doesn't seem like a good thing that two of us have such different ideas
about what the order should be.

I wouldn't mind just making positional associations illegal in some situations
(such as any time the aggregate type or an ancestor is a derived type with
discriminants).  Unfortunately, it would be an incompatible change, and I know
of existing code that would be affected.

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

From: Christoph Grein
Sent: Friday, March 11, 2011  12:07 AM

> My understanding has been that you take the components (including the
> discriminants) of the ultimate ancestor type, followed by the
> components of the type derived from that, and so on, until you get to
> the type of the aggregate, and then select the needed components
> keeping the same order.  So a component of a parent type would come
> before a discriminant of a child type.

Just to oppose my understanding:

You put down the components in the order you read them from left to right (resp.
top down) in the type declaration: Aha, the type has a discriminant, so put this
down. Next it's derived from some type, let's look there; go on like this until
you come to the ultimate ancestor. Only then are you back at the type you
started with and put down the components in the extension record.

Both methods can be seen as intuitive. (I asked a collegue, and he arrived at
Adam's sequence.)

> But it doesn't seem like a good thing that two of us have such
> different ideas about what the order should be.

Yes, exactly.

BTW: I have not yet had an opportunity to use streaming, but also there the
discriminants come first (they have to or you couldn't construct the value). So,
according to what you say, positional aggregates have a different order from
streaming.

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

From: Steve Baird
Sent: Friday, March 11, 2011   7:06 PM

> BTW: I have not yet had an opportunity to use streaming, but also
> there the discriminants come first (they have to or you couldn't
> construct the value). So, according to what you say, positional
> aggregates have a different order from streaming.

I don't think there is a problem with streaming because discriminants of a
non-limited tagged type cannot have defaults.

This means that for tagged types, default implementations of Read/Write
attributes read/write only non-discriminant components while Input/Outout
attributes read/write only discriminants (before calling Read/Write),

Since none of these read/write both discrims and non-discrims, the question of
their relative places in the "positional aggregate ordering" of components never
comes up.

Ok, maybe one could construct a pathology such as

    package Pkg is
        subtype Index is Integer range 1 .. 100;
        type T1 (D1, D2 : Index) is private;
    private
        type T1 (D1, D2 : Index) is new
           Some_Tagged_Discriminated_Type (D1, D2) with
              record F : String (D1 .. D2); end record;
    end Pkg;

    type T2 (D3 : Pkg.Index := 50) is new Pkg.T1 (D3, D3);

and then wonder about what "positional aggregate order"
mans for such a type. Let's not.

While looking at this, I did notice a minor wording issue.

In 13.13.2(26), the parenthesized wording eems wrong:

    If T has discriminants without defaults, S'Output first writes the
    discriminants (using S'Write for each), and S'Input first reads the
    discriminants (using S'Read for each).

S is a discriminated subtype. We are using S'Write and S'Read to write/read
single discriminant values? Probably "using S'Write" should be replaced with
something like "using the Write attribute of each dicriminant type", and
similarly for Read.

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

From: Adam Beneschan
Sent: Thursday, March 17, 2011   8:44 PM

I just found a case where it appears that my understanding will fail
miserably:

   type Type1 (B : Boolean) is tagged record
      Comp1 : Integer;
      case B is
         when False =>
            Comp2 : Boolean;
         when True =>
            null;
      end case;
   end record;

   type Type2 (B2 : Boolean) is new Type1 (B => B2) with record
      Comp3 : Integer;
   end record;

I'm pretty sure that inherited discriminants aren't "needed" if the subtype of
the ancestor type is constrained.  So the needed components inherited from Type1
depend on B2, and will be Comp1 if B=True and Comp1, Comp2 if B=False.  Also, B2
is a needed component.  But if the needed components from Type1 are listed in a
positional aggregate before the discriminant of the child type (i.e. B2), we're
stuck. When the compiler tries to parse

   Type2' (100, True, ...

it can't tell whether True is supposed to be associated with Comp2 or B2, and
I'm sure that we don't want to require that compilers look ahead to figure this
out.

So either Christoph has to be right, or else positional associations should just
be made illegal in some cases.

P.S. I certainly don't expect this to be resolved for Ada 2012.  I think that
for now, I'm going to try to make our compiler just reject positional
associations in cases involving variant parts and type extensions with
discriminants, and I doubt anyone will complain.

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

From: Christoph Grein
Sent: Friday, March 18, 2011  6:18 AM

It seems that Rational follows my interpretation:

package Pack is

  type S (Disc: Boolean) is tagged record
    F: Float;
    case Disc is
      when False => I: Integer;
      when True  => null;
    end case;
  end record;

  type T (X: Boolean) is new S (X) with null record;

  -- accepted
  VT_F1: constant T := (True , 1.0);
  VT_T1: constant T := (False, 1.0, 1);

  -- rejected
  VT_F2: constant T := (1.0, True);
  VT_T2: constant T := (1.0, 1, False);

end Pack;

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

From: Gary Dismukes
Sent: Friday, March 18, 2011  1:21 PM

Christoph interpretation is correct, and there's no need to make positional
aggregate for such types illegal (fortunately!).

The language is clear about the relative order of declarations of discriminants
and other components, and discriminants definitely come first (whether new or
inherited).  This is defined in 3.4(10-14):

   10  If the parent type is a composite type other than an array type,
       then the components, protected subprograms, and entries that are
       declared for the derived type are as follows:

          11  The discriminants specified by a new known_discriminant_
              part, if there is one; otherwise, each discriminant of the
              parent type (implicitly declared in the same order with
              the same specifications) -- {inherited discriminant}
              {inherited component} in the latter case, the dis-
              criminants are said to be inherited, or if unknown in the
              parent, are also unknown in the derived type;

          12  Each nondiscriminant component, entry, and protected
              subprogram of the parent type, implicitly declared in the
              same order with the same declarations; {inherited
              component} {inherited protected subprogram} {inherited
              entry} these components, entries, and protected sub-
              programs are said to be inherited;

          13  Each component declared in a record_extension_part, if
              any.

       14   Declarations of components, protected subprograms, and
       entries, whether implicit or explicit, occur immediately within
       the declarative region of the type, in the order indicated above,
       following the parent subtype_indication.

Just guessing, but I think maybe you got off track by thinking of the parent
type(s) as somehow being part of the declarative region of the type in question,
but it's only the declaration order of the components (both implicit and
explicit) within the type in question that matters.

> P.S. I certainly don't expect this to be resolved for Ada 2012.  I
> think that for now, I'm going to try to make our compiler just reject
> positional associations in cases involving variant parts and type
> extensions with discriminants, and I doubt anyone will complain.

Please don't, as I believe this is all very well defined and works as desired
wrt variant cases. :-)

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

From: Adam Beneschan
Sent: Friday, March 18, 2011  1:44 PM

> Just guessing, but I think maybe you got off track by thinking of the
> parent type(s) as somehow being part of the declarative region of the
> type in question, but it's only the declaration order of the
> components (both implicit and explicit) within the type in question that matters.

The problem was that I didn't think to look in 3.4.  I looked in several
sections to try to figure out the answer to my question, including 3.7, but I
didn't think to look in this one.  Unfortunately, I don't have the whole RM
memorized, and I can't read the entire RM every time I had a question.  So if
the sections that I guess to look at don't answer the question and don't point
me to the right answer, I get stuck.  I'm sure it's not feasible to have the
AARM have every possible needed cross-reference, so I guess in a case like this
I have to rely on a resource like this list and hope that someone (like you)
remembers enough so that they can point me in the right direction. Thanks.

So I guess that this settles things.

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

From: Randy Brukardt
Sent: Friday, March 18, 2011  3:22 PM

If it makes you feel any better, I had no idea that the text Gary quoted exists,
and thought that there was a real problem here. 3.4 would not have been the
first place I would have thought to look, either.

I don't think anyone can have the entire RM memorized; it's not that unusual for
me to be surprised about language rules, or for me to be surprised that some
other ARG member doesn't know about some rule that I remember well.

That's one of the reasons that lists like this exist.

I think there might be some value to an AARM note in 4.3.1 referencing 3.4 as
defining the order of components in derived types. (I think it only matters in
4.3.1, and to a lesser extent in 13.13.2.)

But in general, we can't imagine ahead of time what people will be surprised
about, so all possible notes can't really exist.

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

From: Gary Dismukes
Sent: Friday, March 18, 2011  3:53 PM

> ... I'm sure it's not feasible to have the AARM have every
> possible needed cross-reference, so I guess in a case like this I have
> to rely on a resource like this list and hope that someone (like you)
> remembers enough so that they can point me in the right direction.
> Thanks.

I hope it didn't sound like I thought this was obvious, or that you should have
found it.  Until today I was rather distracted by other ARG work over the last
week or so, and had read this ada-comment mail in passing, but hadn't had time
to think about it till now. It sounded like you might have uncovered a real
problem.  When I saw today's mail from you and Christoph it caused me to take a
closer look, as it seemed that perhaps something was being overlooked.

> So I guess that this settles things.

I think so.  Anyway, sorry I wasn't able to chime in sooner to clear this up!

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

Questions? Ask the ACAA Technical Agent