aliased discriminant record components 
Author Message
 aliased discriminant record components

Calling all Ada experts...

I am having trouble declaring a record type with an aliased component of
a discriminant type.

    type A( B : Boolean ) is record ... end record;
    type C is record
       AA : aliased A;
    end record;

The error message I am getting is:

   "aliased component must be constrained"

Can anyone explain the rules here to me, please ?

I have looked in both Barnes and Cohen but without any joy.

ARM 3.10(9) says: "If the view defined by an object_declaration is
aliased, and the type of the object has discriminants, then the object
is constrained; if its nominal subtype is unconstrained, then the object
is constrained by its initial value".

Not for the first time have I hesitantly concluded that I might have
found the relevant section of the ARM but then cannot understand it.

Thanks for any help.

Best -- Anton Gibbs.

--
Civil Air Traffic Management Group
Defence Evaluation and Research Agency
Bedford, UK

"The Information contained in this E-Mail and any
subsequent correspondence is private and is intended
solely for the intended recipient(s).  For those
other than the intended recipient any disclosure,
copying, distribution, or any action taken or
omitted to be taken in reliance on such information
is prohibited and may be unlawful."



Mon, 23 Dec 2002 03:00:00 GMT  
 aliased discriminant record components


Quote:

> Calling all Ada experts...

> I am having trouble declaring a record type with an aliased component of
> a discriminant type.

>     type A( B : Boolean ) is record ... end record;
>     type C is record
>        AA : aliased A;
>     end record;

> The error message I am getting is:

>    "aliased component must be constrained"

> Can anyone explain the rules here to me, please ?

Just like the message says... the AA component must be constrained -- i.e,
        AA : aliased A (True);
or
        AA : aliased A (False);

Quote:
> I have looked in both Barnes and Cohen but without any joy.

I fail to understand how the compiler message could be more clear, or
what elucidation these books might have provided.

Quote:
> ARM 3.10(9) says: "If the view defined by an object_declaration is
> aliased, and the type of the object has discriminants, then the object
> is constrained; if its nominal subtype is unconstrained, then the object
> is constrained by its initial value".

The ARM is talking about objects, but you have no objects in the
code snippet you provided -- you have only two types.

Quote:
> Not for the first time have I hesitantly concluded that I might have
> found the relevant section of the ARM but then cannot understand it.

This secion doesn't seem relevant to me.

- Show quoted text -

Quote:

> Thanks for any help.

> Best -- Anton Gibbs.

> --
> Civil Air Traffic Management Group
> Defence Evaluation and Research Agency
> Bedford, UK

> "The Information contained in this E-Mail and any
> subsequent correspondence is private and is intended
> solely for the intended recipient(s).  For those
> other than the intended recipient any disclosure,
> copying, distribution, or any action taken or
> omitted to be taken in reliance on such information
> is prohibited and may be unlawful."



Mon, 23 Dec 2002 03:00:00 GMT  
 aliased discriminant record components

Quote:

> Calling all Ada experts...

Hmmm... I guess I'll do in a pinch.

Quote:
> I am having trouble declaring a record type with an aliased component of
> a discriminant type.

>     type A( B : Boolean ) is record ... end record;
>     type C is record
>        AA : aliased A;
>     end record;

> The error message I am getting is:

>    "aliased component must be constrained"

> Can anyone explain the rules here to me, please ?

This restriction is motivated by a feature of the language called
"access subtypes."

The Ada type model is that you have a base type, which comprises all
possible values, and subtypes of that base type, which specify some
(contiguous) subset of values from the set.  

For example, I have type Integer (which is really a "first-named
subtype," but let's not quibble), which comprises a set of integer
values, and it's subtype Natural, which names the subset of Integer
without an negative values.

I can declare a discriminated record like this:

type DT is (A, B, C);

type RT (D : DT := DT'First) is record
   case D is
      when A =>
         I : Integer;
      when B =>
         F : Float;
      when C =>
         Bool : Boolean;
   end case;
end record;

So when I see this:

procedure Op (O : RT) is ...

I know that object O can have a discriminant whose value is A or B or
C; I have to interrogate the value to know which.

However, I can declare a subtype of RT, like this:

subtype ART is RT (A);

which names the subset of values of base type RT having a discriminant
with the value A.  When I see this:

procedure Op (O : ART) is ...

then I don't have to test the value of the discriminant of O, because I
know it has to have the value A.  (Constraint violations are checked at
the point of call.)

Analogous to integer subtypes, floating point subtypes, discriminated
record subtypes, etc, there can also be access subtypes.

For example, I can declare an access type that designates the
discriminated record type we declared above:

type RT_Access is access all RT;

When I see something like this:

  O : RT_Access;

then I know access object O can designate an object whose discriminant
can have any of the values A or B or C.

However, I can declare a subtype of RT_Access, like this:

subtype ART_Access is RT_Access (A);

that constrains the values that may be designated, to the subset having
the value A as a discriminant.

When I see something like this:

  O : ART_Access;

than I know access object O can designate an object whose discriminant
has to have the value A.  

Now, with this introduction to the Ada type model out of the way, we can
finally answer your original question.  

If I have an access object of (sub)type ART_Access, then the language is
making a promise that all objects designated have value A as their
discriminant.  For example, suppose this were allowed:

declare
  R : aliased RT := (D => A, ...); --illegal
  O : ART_Access := R'Access;
begin
  O.I := 5;  
...
end;

Everything's hunky-dory here: object R has a discriminant A, and access
object O designates a value having the proper constraint, so the
assignment to the I component is, um, "A" OK.

Now suppose we were allowed to do this:

declare
  R : aliased RT := (D => A, I => 2);  --illegal
  O : ART_Access := R'Access;
begin
  R := (D => B, F => 2.5);
  O.I := 5;  --???
end;

The language has made a promise that all objects designated by O have A
as their discriminant (and hence have Integer component I).  However,
we've gone ahead an changed the descriminant of R behind O's back!
Thus, the language has reneged on its promise.

Through object O, an assignment to component I was made.  However, the
object designated by O (here, object R) doesn't have I as a component,
because it has a different discriminant.

Therefore, the language is designed such that objects which are aliased
must also have a constrained discriminant.  The reason for this
restriction is because of access subtypes.

This also explains why discriminated records allocated from the heap
must be constrained: because they can potentially be designated by an
access subtype.

If you don't need a mutable value, then you can supply a constraint,
like this:

declare
  R : aliased RT(A) := (D => A, I => 2);
  O : ART_Access := R'Access;
begin

Now all is well, because object R is constrained.

Of course, if you don't need the object to be aliased, then you're free
to declare a mutable object.

Another way to solve the problem is to wrap the object in a
non-discriminated type:

declare
  type RT_Wrapper_Type is record
     Inner : RT;  --mutable
  end record;

  R : aliased RT_Wrapper_Type;
...

Now all is well, because you're designating a type (here,
RT_Wrapper_Type) that doesn't have a discriminant.  Yet the object it
points to (here, R.Inner) is still mutable.

This feature of the language ("aliased object must be constrained")
surprises almost all new users.  It did in Ada83, and continues to do so
in Ada95.  With hindsight, including access subtypes as a language
feature was probably a mistake.  

Hope this clears things up.

Matt



Tue, 24 Dec 2002 03:00:00 GMT  
 aliased discriminant record components

Quote:

> This restriction is motivated by a feature of the language called
> "access subtypes."
> Therefore, the language is designed such that objects which are aliased
> must also have a constrained discriminant.  The reason for this
> restriction is because of access subtypes.
> This feature of the language ("aliased object must be constrained")
> surprises almost all new users.  It did in Ada83, and continues to do so
> in Ada95.  With hindsight, including access subtypes as a language
> feature was probably a mistake.

Dear Matt,

     Thank you for the very thorough explanation of my problems
declaring unconstrained objects which are aliased.

One thing that threw me was the apparent inconsistency between an object
declared in its own right and the same thing declared as a record
component.

For instance:

   declare
      R : aliased RT;
   begin

is accepted but silently constrains R to the default discriminant (with
potential surprise at run-time).

Whereas:

   declare
      type Rec is
      record
         R : aliased RT;
      end record;
   begin

is rejected with "aliased component must be constrained".

Strikes me it would be better if the first declaration was rejected as
well so that the constraint had to be explicitly included and thereby
documents that fact that the object is constrained. But presumably there
is some additional language subtlety here which is eluding me ... ;-)

Your suggested work-around of using a non-discriminant wrapper type
seems good to me - I'll try that. Thanks.

Anton Gibbs.

--
Civil Air Traffic Management Group
Defence Evaluation and Research Agency
Bedford, UK

"The Information contained in this E-Mail and any
subsequent correspondence is private and is intended
solely for the intended recipient(s).  For those
other than the intended recipient any disclosure,
copying, distribution, or any action taken or
omitted to be taken in reliance on such information
is prohibited and may be unlawful."



Fri, 27 Dec 2002 03:00:00 GMT  
 aliased discriminant record components

Quote:

> One thing that threw me was the apparent inconsistency between an object
> declared in its own right and the same thing declared as a record
> component.

I don't think there should be any difference between these two cases.

Quote:
> For instance:

>    declare
>       R : aliased RT;
>    begin

> is accepted but silently constrains R to the default discriminant (with
> potential surprise at run-time).

This seems wrong to me.  An aliased object is an aliased object; it
shouldn't matter whether the object is declared as a record component.

I think this declaration is illegal, and your compiler isn't flagging
it.  But then again, I could be wrong.  Maybe the rule is that because
the object is declared in a scope without access subtypes, then it's OK.

I'm suspicious, though, that the compiler "silently contrains" the
subtype of object R.  This doesn't seem right to me, which makes me
think there's a compiler bug.

Quote:
> Whereas:

>    declare
>       type Rec is
>       record
>          R : aliased RT;
>       end record;
>    begin

> is rejected with "aliased component must be constrained".

My assumption is that the earlier declaration should have been rejected
too.  

Quote:
> Strikes me it would be better if the first declaration was rejected as
> well so that the constraint had to be explicitly included and thereby
> documents that fact that the object is constrained. But presumably there
> is some additional language subtlety here which is eluding me ... ;-)

I'm not sure.  I think you may have a compiler bug.  What compiler are
you using?  Send them a bug report and see what they say.

Quote:
> Your suggested work-around of using a non-discriminant wrapper type
> seems good to me - I'll try that. Thanks.

That's the standard work-around for this, um, "feature" of the language.

Matt



Fri, 27 Dec 2002 03:00:00 GMT  
 aliased discriminant record components

Quote:

> I think you may have a compiler bug.  What compiler are
> you using?  Send them a bug report and see what they say.

I am using gnat 3.13a1.

I am not at all sure this is a genuine compiler bug or just a quirk of
the language but I will go ahead and submit a bug report anyway.

Cheers -- Anton.

--
Civil Air Traffic Management Group
Defence Evaluation and Research Agency
Bedford, UK

"The Information contained in this E-Mail and any
subsequent correspondence is private and is intended
solely for the intended recipient(s).  For those
other than the intended recipient any disclosure,
copying, distribution, or any action taken or
omitted to be taken in reliance on such information
is prohibited and may be unlawful."



Sat, 28 Dec 2002 03:00:00 GMT  
 
 [ 6 post ] 

 Relevant Pages 

1. Why un-aliased Stream_Element_Array components?

2. Help: Dynamic-size arrays using record discriminant.

3. GNAT's internal format for Discriminant Records?

4. Help with a constant of a discriminant record type

5. ABC - Prime Record in multi component key ( C5002 )

6. Memory representation of variable length record components

7. Finalization of record components which are tasks

8. Aligning record components

9. constant record components in Ada

10. Record component positions always constant?

11. Question about anonymous arrays as record components

12. record component selector in init

 

 
Powered by phpBB® Forum Software