Version 1.3 of ais/ai-00338.txt

Unformatted version of ais/ai-00338.txt version 1.3
Other versions for file ais/ai-00338.txt

!standard 3.07.02 (02)          03-07-31 AI95-00338/00
!class amendment 03-07-31
!status No Action (10-0-0) 03-10-04
!status received 03-01-13
!priority Low
!difficulty Easy
!subject Constrained attribute for generic formal private types
!summary
!problem
!proposal
!wording
!example
!discussion
!corrigendum 03.07.02(02)
!ACATS test
!appendix

!topic constrained attribute for generic formal private types
!reference RM95-3.7.2/2
!from Dan Eilers 03-01-13
!discussion


RM95 3.7.2/2 appears to disallow 'constrained on objects of a
generic formal private type, such as:

    generic
       type T (<>) is private;
    package P is
       pragma elaborate_body;
    end P;

    package body P is
       procedure p1 (x: out T) is
       begin
          if x'constrained ...          -- why not?
       end p1;
    end P;


It seems useful to allow this, presumably yielding true for
actual types for which 'constrained is currently disallowed.

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

From: Christoph Grein
Sent: Wednesday, January 15, 2003  1:33 AM

Gnat 3.16w compiles this (with a warning that x is never assigned a value), in
contradiction to 3.7(8/1).

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

From: Randy Brukardt
Sent: Thursday, July 31, 2003  5:41 PM

Sorry about commenting on an ancient issue, but I needed to get it on the
record:

> !topic constrained attribute for generic formal private types
> !reference RM95-3.7.2/2
> !from Dan Eilers 03-01-13
> !discussion
>
>
> RM95 3.7.2/2 appears to disallow 'constrained on objects of a
> generic formal private type, such as:
>
>     generic
>        type T (<>) is private;
>     package P is
>        pragma elaborate_body;
>     end P;
>
>     package body P is
>        procedure p1 (x: out T) is
>        begin
>           if x'constrained ...          -- why not?
>        end p1;
>     end P;
>
> It seems useful to allow this, presumably yielding true for
> actual types for which 'constrained is currently disallowed.

This is allowed (in fact required) by J.4 The Constrained Attribute

S'Constrained is in fact defined for all private subtypes.

The AARM claims it is obsolete because Ada 95 has
unknown_discriminant_parts. Precisely why a compile-time feature would
obsolete a useful run-time feature is never quite explained. :-)

Anyway, there is no issue here (unless someone wants to argue that the
attribute shouldn't be obsolete).

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

From: Randy Brukardt
Sent: Thursday, July 31, 2003  6:10 PM

I said:

> This is allowed (in fact required) by J.4 The Constrained Attribute
>
> S'Constrained is in fact defined for all private subtypes.

Oops -- he asked for this on an object, not on a subtype.

It's interesting that these two definitions of the Constrained attribute
were taken almost unchanged from Ada 83.

Anyway, defining this on a generic formal private object is somewhat
confusing (as noted in J.4 of the AARM). If the formal type is instantiated
with a scalar subtype without constraints, Obj'Constrained would return
True. But the language says that such a type (and thus such an object) is
unconstrained. As J.4 says, the attribute really would be
'Constrained_or_Elementary.

Given this, I think we need a little more justification for the need of this
attribute; it's possible that we need something other than 'Constrained to
fill the need.

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

From: Tucker Taft
Sent: Thursday, July 31, 2003  6:01 PM

Unfortunately, I don't think your response is "responsive" ;-).

The Constrained attribute in Annex J is a compile-time (well, really
an instantiation-time) attribute of private *subtypes*.
Dan is asking about the Constrained attribute on *objects*
which is non-obsolete and is defined in 3.7.2.

Dan's point is there is no harm in allowing the Constrained
attribute to apply to types with unknown discriminants.
Currently it is limited to *discriminated* types, i.e.
types with known discriminants.  I would agree there seems
no harm in allowing this attribute more generally, and it
would only yield False if the actual type happens to have
discriminants and the discriminants of the actual object or
parameter can be altered by an assignment.

The wording might be a bit tricky...

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

From: Randy Brukardt
Sent: Thursday, July 31, 2003  6:16 PM

> Unfortunately, I don't think your response is "responsive" ;-).

You should have at least waited for my retraction. :-)

...
> The wording might be a bit tricky...

That's right, but as is pointed out by you or Bob in J.4, that doesn't
correspond to the meaning of "constrained" in Ada 95. It seems odd to define
a non-obsolete Constrained attribute to return something other than whether
the object is constrained or not.

The problem really is with the use of the constrained terminology in Ada 95
("constrained" for composite types is very different than "constrained" for
elementary types, and probably shouldn't use the same name), but it's too
late to change that.

The concept that you've defined is really "Mutable", not "Constrained". It's
unfortunate that mutable never got defined in the language standard, since it
is a much more useful concept.

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

From: Tucker Taft
Sent: Thursday, July 31, 2003  7:24 PM

Or to be precise, 'Constrained => not 'Mutable.

In your discussion, I think you are still confusing
the subtype'Constrained and the object'Constrained.
The stuff in the annex J AARM is all about the subtype'Constrained
attribute.

The object'Constrained attribute is currently only defined on discriminated
types.  Generalizing it to be defined on all *composite* types
seems reasonable, remembering that the private view of a type is
considered composite.  The tricky part is defining what it would
mean in the instance (or the private part in the case of a "package private"
type), where the actual/full type is not composite.  It seems simplest
to say that the (composite) private view of an elementary object
is always considered 'Constrained.

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

From: Randy Brukardt
Sent: Thursday, July 31, 2003  8:29 PM

> The tricky part is defining what it would mean in the instance (or the
> private part in the case of a "package private" type), where the
> actual/full type is not composite.  It seems simplest
> to say that the (composite) private view of an elementary object
> is always considered 'Constrained.

Of course. And that is what I was objecting to, since the object is not
constrained in language terms. That is:

    Obj'Constrained /= Obj is a constrained object

That seems confusing. Heck, that IS confusing -- they read identically to
me. Moreover, that seems to be the primary reason that S'Constrained was
made obsolete. (The other reason boils down to it not being as useful as it
was, but that hardly is a reason for obsoleting something.)

In any case, we need a !problem for this amendment, and so far, all we have
is that "it seems reasonable", which is not a reason for any amendment. We
need some problem that can't be solved without some language change, and
then we can see if this is the best way to solve the problem. Otherwise,
this is just a solution in search of a problem.

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

From: Tucker Taft
Sent: Thursday, July 31, 2003  8:44 PM

> In any case, we need a !problem for this amendment, and so far, all we have
> is that "it seems reasonable", which is not a reason for any amendment. We
> need some problem that can't be solved without some language change, and
> then we can see if this is the best way to solve the problem. Otherwise,
> this is just a solution in search of a problem.

I agree with this.  Perhaps Dan can provide a convincing example.

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

From: Dan Eilers
Sent: Thursday, July 31, 2003  9:03 PM

I believe this is a GNAT extension that would probably be
generally useful.

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

From: Randy Brukardt
Sent: Thursday, July 31, 2003  9:30 PM

It could just as well be a GNAT bug -- they have as many as everyone else.

So far, we have the reasons for this as "it seems reasonable" and "probably
generally useful". There are lots of proposals with better justifications
than that that aren't going to be in the Amendment. Why is this one
different?

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

From: Dan Eilers
Sent: Thursday, July 31, 2003  10:24 PM

Maybe it's different because it implicates the fundamental language design
goal of orthogonality.  Non-generic units should generally be readily
convertible into generic units, regardless of language features used.
But in this case, a non-generic unit that uses the 'constrained attribute
on an object can't be converted into a generic with the object's type as
a generic parameter.

If this is a GNAT bug, it seems to be a good bug, since it makes something
legal that has a natural meaning, and does not fall under any of the
usual categories for making something illegal, such as being somehow
hazardous to the user or difficult to implement.

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

From: Randy Brukardt
Sent: Thursday, July 31, 2003 10:47 PM

> Maybe it's different because it implicates the fundamental language design
> goal of orthogonality.  Non-generic units should generally be readily
> convertible into generic units, regardless of language features used.
> But in this case, a non-generic unit that uses the 'constrained attribute
> on an object can't be converted into a generic with the object's type as
> a generic parameter.

Fair enough. But if that was solely a reason for making changes, we'd have
dumped the generic contract model and generic sharing long ago, as they both
interfere with that.

> If this is a GNAT bug, it seems to be a good bug, since it makes something
> legal that has a natural meaning, and does not fall under any of the
> usual categories for making something illegal, such as being somehow
> hazardous to the user or difficult to implement.

It's hazardous to understanding the language, because
    Obj'Constrained /= Obj is a constrained object
I worry about introducing this confusion into the language for what appears
to be a pretty useless feature. (At least it is never used in any of our
major software; I just did a Find, which only turned up a bunch of comments
about implementing it in the compiler, nothing at all in Claw.)

Perhaps understanding the meaning of 'constrained' isn't important. Perhaps
no one understands it now, so it doesn't hurt to return something else. But
I'd feel better if this attribute was actually useful for something. Which
is why I'd like to see a solid example of its use.

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

From: Dan Eilers
Sent: Friday, August  1, 2003  12:13 AM

The only use I know of is in the GNAT runtime (in a-direio.adb and
a-sequio.adb).

generic
   type Element_Type is private;

package Ada.Direct_IO is

...

   procedure Read
     (File : in File_Type;
      Item : out Element_Type;
      From : in Positive_Count)
   is
   begin
      --  For a non-constrained variant record type, we read into an
      --  intermediate buffer, since we may have the case of discriminated
      --  records where a discriminant check is required, and we may need
      --  to assign only part of the record buffer originally written

      if not Element_Type'Constrained then
         declare
            Buf : Element_Type;

         begin
            DIO.Read (FP (File), Buf'Address, Bytes, DPCount (From));
            Item := Buf;
         end;

      --  In the normal case, we can read straight into the buffer

      else
         DIO.Read (FP (File), Item'Address, Bytes, DPCount (From));
      end if;
   end Read;

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

From: Randy Brukardt
Sent: Friday, August 1, 2003  1:21 AM

The wording of 3.7.2(3) doesn't make it clear whether it is talking about
views or objects. That matters, because an in parameter is a constant view,
but it probably isn't a constant object.

The AARM makes it clear that the expectation is that the attribute is always
True for an in parameter. However, this doesn't seem to follow from the
wording. "A denotes a constant" seems to be talking about the object, not
the view. The only other place that uses that terminology (6.5) says "the
function call denotes a constant view...".

This wording should be tightened up, especially if the proposed change is
made.

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

From: Pascal Leroy
Sent: Friday, August 1, 2003  1:11 AM

> The only use I know of is in the GNAT runtime (in a-direio.adb and
> a-sequio.adb).
>
> generic
>    type Element_Type is private;
>
> package Ada.Direct_IO is
>
> ...
>
>       if not Element_Type'Constrained then

But this is the attribute of a _subtype_, not the attribute of an
_object_.  Clearly the above usage is important (we have essentially the
same code in our implementation of the I/O packages), but that doesn't
say anything about Object'Constrained.

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

From: Dan Eilers
Sent: Friday, August  1, 2003  1:31 AM

The other example, in a-sequio.adb, does use an object:

generic
   type Element_Type (<>) is private;

package Ada.Sequential_IO is

...

   procedure Read (File : in File_Type; Item : out Element_Type) is
      Siz  : constant size_t := (Item'Size + SU - 1) / SU;
      Rsiz : size_t;

   begin
      FIO.Check_Read_Status (AP (File));

      --  For non-definite type or type with discriminants, read size and
      --  raise Program_Error if it is larger than the size of the item.

      if not Element_Type'Definite
        or else Element_Type'Has_Discriminants
      then
         FIO.Read_Buf
           (AP (File), Rsiz'Address, size_t'Size / System.Storage_Unit);

         --  For a type with discriminants, we have to read into a temporary
         --  buffer if Item is constrained, to check that the discriminants
         --  are correct.

         pragma Extensions_Allowed (On);
         --  Needed to allow Constrained reference here

         if Element_Type'Has_Discriminants
>>>>       and then Item'Constrained
         then
            declare
               RsizS : constant SSE.Storage_Offset :=
                         SSE.Storage_Offset (Rsiz - 1);

               subtype SA is SSE.Storage_Array (0 .. RsizS);
               type SAP   is access all SA;
               type ItemP is access all Element_Type;

               pragma Warnings (Off);
               --  We have to turn warnings off for this function, because
               --  it gets analyzed for all types, including ones which
               --  can't possibly come this way, and for which the size
               --  of the access types differs.

               function To_ItemP is new Unchecked_Conversion (SAP, ItemP);

               pragma Warnings (On);

               Buffer : aliased SA;

               pragma Unsuppress (Discriminant_Check);

            begin
               FIO.Read_Buf (AP (File), Buffer'Address, Rsiz);
               Item := To_ItemP (Buffer'Access).all;
               return;
            end;
         end if;

         --  In the case of a non-definite type, make sure the length is OK.
         --  We can't do this in the variant record case, because the size is
         --  based on the current discriminant, so may be apparently wrong.

         if not Element_Type'Has_Discriminants and then Rsiz > Siz then
            raise Program_Error;
         end if;

         FIO.Read_Buf (AP (File), Item'Address, Rsiz);

      --  For definite type without discriminants, use actual size of item

      else
         FIO.Read_Buf (AP (File), Item'Address, Siz);
      end if;
   end Read;

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

From: Randy Brukardt
Sent: Friday, August 1, 2003  9:28 PM

But this is very compiler-dependent code. Besides "pragma Extensions", it also
uses "'Has_Discriminants" (which is not an Ada attribute) and then does other
non-portable fiddling. That hardly seems to be a reason for adding something to
the language; every implementer has to add various junk to implement the
runtime. But that's all very implementation-dependent.

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


Questions? Ask the ACAA Technical Agent