Version 1.3 of ais/ai-00051.txt

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

!standard 13.03 (42)          99-03-22 AI95-00051/09
!class binding interpretation 95-06-25
!status work item 98-04-01
!status ARG Approved (subject to letter ballot) 8-0-2 97-11-14
!status work item (letter ballot was 4-4-3) 96-10-03
!status letter ballot requested
!status work item (letter ballot was 8-2-1) 96-06-05
!status ARG approved (subject to letter ballot) ??? 95-11-01
!status received 95-06-25
!reference AI95-00109
!priority High
!difficulty Medium
!subject Size and Alignment Clauses for Objects
!summary 99-03-22
This AI addresses the requirements for which Size and Alignment clauses must be supported for objects. For Size and Alignment of subtypes, see AI95-00109. This AI also addresses various representation items when applied to aliased objects.
The following Recommended Level of Support is added:
1. The implementation should support a Size or Alignment clause for an object if it specifies the same Size or Alignment that the implementation would have chosen by default.
2. For an aliased object, the implementation need not support a representation clause that causes the object to have a Size or Alignment that is different from what the implementation would have chosen by default. (For aliased stand-alone objects, this applies to Size and Alignment clauses. For aliased record or record extension components, this applies to component_clauses. For aliased array components, this applies to Component_Size clauses.) For a pragma Pack, the implementation need not pack an aliased component in such a way that gives it a different Size or Alignment than it would have without the pragma Pack.
3. For a non-aliased object, the implementation should support a Size clause specifying a Size up to (at least) the following values, which depends on the class of the object. (Similarly, the implementation should support a Component_Size clause and a record_representation_clause specifying the Size of a component up to (at least) these values, depending on the class of the component.)
- For a signed integer, up to the Size of the largest signed integer
type supported by the implementation.
- For a modular integer, up to the Size of the largest modular
type supported by the implementation.
- For an object of an enumerated type, up to the Size of the largest
signed integer type, or the largest modular type, whichever is smaller.
For fixed point, floating point, access, and composite objects, the implementation need not support any Size other than what would be chosen by default.
In the discrete case, any extra bits are set to appropriate values when assigning to the object whose Size has been specified; for example, the value being assigned should be zero-extended or sign-extended as appropriate. When reading from the object, any extra bits may be ignored.
In the composite case, any extra bits may be ignored, and may be left undefined.
4. For a non-aliased object, the implementation need not support an Alignment clause unless the Alignment evenly divides the size (in storage elements) of the object.
In addition, the following Implementation Advice (not Recommended Level of Support) is added:
For Mutable_Obj'Size, where Mutable_Obj denotes a view of an object whose type has discriminants with defaults: If the view is unconstrained, the Size should reflect the total size allocated for the object. If the view is constrained, the Size should reflect the current size of the object, given its current discriminant values.
!question 96-09-05
First question: The recommended level of support for the Size attribute of an object (in RM-13.3(42,43)) implies that the following should be accepted:
X: Integer; for X'Size use 1024;
Is this the intent? If so, what should be done with the extra 922 bits (if Integer'Size = 32)? If X is passed as a parameter, must all 1024 bits be copied? (Presumably not, since the callee won't be expecting them.)
----------------
Second question: What is the meaning of the Size attribute for an unconstrained variable that is of a mutable type? Consider:
subtype Small_Natural is Natural range 0..100; type Mutable(Len: Small_Natural := 0) is record Chars: String(1..Len); end record; X: Mutable;
Suppose the implementation allocates the maximum possible size for X (perhaps 104 bytes). The "current size" of the value of X (i.e. the "constrained size", with Len constrained to 0) is perhaps just 4 bytes (for Len -- the Chars field is empty). Should X'Size be the current size (perhaps 48) or the maximum size (perhaps 1048)? The RM does not answer this question.
!recommendation 96-04-17
(See summary.)
!wording 96-04-17
!discussion 96-11-16
First question:
Clearly, an implementation ought to support "confirming" Size and Alignment clauses, and there is little burden in doing so.
The restrictions on Size and Alignment clauses for aliased objects are necessary, because one can form a pointer to an aliased object (either an access value, or a value of type Address). Dereferences through the pointer will not know about any Size or Alignment clause on the object. For example, suppose Integer'Size = 32:
type Int_Ptr is access all Integer; X: aliased Integer; for X'Size use 64; Y: Int_Ptr := X'access;
Now, depending on where the extra bits are allocated, a dereference of Y might get the "wrong" 32 bits.
The same reasoning applies to component_clauses and Component_Size clauses, since these can affect the Size and Alignment of the components.
The same reasoning applies to pragma Pack, except that instead of refusing to support the pragma, the implementation should avoid packing the aliased component(s) too tightly.
Note that on some machines, it may be feasible to support some Size or Alignment clauses that are not required by point (2) of the Summary. Thus, point (2) says "need not" (as opposed to "should not" or "must not"). For example, on some machines, alignment primarily affects the speed of the machine code, rather than its correctness.
As to the restrictions on Size clauses for non-aliased objects, it seems unreasonable to require arbitrarily large values for discrete types. Values up to the maximum supported for the class make sense, since the implementation already knows how to do sign extension or zero extension, as appropriate, for type conversions. The extra bits should not be left undefined, because if one takes the Address of such an object, one expects to have well-defined data in all of its bits. The representation of fixed point, floating point, and access types is often special, so we place no requirements other than to support "confirming" Size clauses. For composite objects, it might be an implementation burden to require arbitrarily large Sizes. For example, one implementation reportedly implements small packed arrays of Booleans in the same manner as modular types. If arbitrarily large Sizes for modular types are not supported, then arbitrarily large Sizes for such packed arrays can't be supported, either, given this (reasonable) implementation strategy.
Relevant wording from the RM follows:
13.3 says:
42 {recommended level of support [Size attribute]} The recommended level of support for the Size attribute of objects is:
43 A Size clause should be supported for an object if the specified
Size is at least as large as its subtype's Size, and corresponds to a size in storage elements that is a multiple of the object's Alignment (if the Alignment is nonzero).
...
54 {recommended level of support [Size attribute]} The recommended level of support for the Size attribute of subtypes is:
55 The Size (if not specified) of a static discrete or fixed point subtype should be the number of bits needed to represent each value belonging to the subtype using an unbiased representation, leaving space for a sign bit only if the subtype contains negative values. If such a subtype is a first subtype, then an implementation should support a specified Size for it that reflects this representation.
These recommendations are hard requirements for implementations that support the Systems Programming Annex, by C.2(2):
2 {recommended level of support [required in Systems Programming Annex]} The implementation shall support at least the functionality defined by the recommended levels of support in Section 13.
13.1(7) says:
7 {representation of an object} {size (of an object)} The representation of an object consists of a certain number of bits (the size of the object). These are the bits that are normally read or updated by the machine code when loading, storing, or operating-on the value of the object. This includes some padding bits, when the size of the object is greater than the size of its subtype. {gaps} {padding bits} Such padding bits are considered to be part of the representation of the object, rather than being gaps between objects, if these bits are normally read and updated.
It is not clear what "bits that are normally read or updated" means for composite types, since assignment and comparison are defined in terms of individual components. For example, on an assignment, there is no requirement that gaps in the middle of the object be copied, so clearly there should be no such requirement on extra bits added to the end of the object. For scalars, however, all bits in the representation of the object should be set to some meaningful value.
----------------
Second question: In the example, X'Size should be the max size. Here's why: Suppose we add a Size clause to the above:
for X'Size use 104*8; -- Specify the Size of the *object*.
Clearly, this will not be legal if 104*8 is less than the max possible size. By 13.1(17), a query of X'Size *must* now return 104*8. 13.1(17.a) gives an example of this. So, in the case of a specified Size (on the object), the query cannot return the current size.
To preserve the principle that confirming rep clauses shouldn't change things, we must use the same rule even when there's not a Size clause.
Now, suppose we have a constrained object:
subtype Mutable_3 is Mutable(Len => 3); Y: Mutable_3; Z: constant Mutable := (Len => 3, Chars => "abc");
Here, the compiler will not allocate the max size. Y'Size and Z'Size should clearly be the constrained Size -- the Size given that Len = 3.
Now, suppose we have a parameter:
procedure Proc(Param1: Mutable; -- Constant; therefore constrained. Param2: in out Mutable3; -- Constrained. Param3: in out Mutable) is begin ... end Proc;
Proc(X, X, X); -- Unconstrained actual parameters. Proc(Y, Y, Y); -- Constrained actual parameters.
Inside Proc, Param1'Size and Param2'Size should be the constrained size, based on the value of the actual parameter's discriminant. The alternative would be to return the max size if the actual parameter denotes an unconstrained object. But that's not really reasonable from an implementation point of view -- inside Proc, we don't know whether the actual denotes an unconstrained object.
For Param3, however, we do know whether the actual is constrained or unconstrained -- it is necessary to pass extra dope to implement the 'Constrained attribute. Therefore, Param3'Size should be the max size, or the constrained size, depending on the constrainedness of the actual view. (Note: we say "view" there because the actual could be another formal -- we should care about the constrainedness of the actual view, not the constrainedness of the actual object.)
Note: all aliased objects are constrained, so the parameter issue does not come up for access values. That is, Ptr.all'Size will clearly always return the constrained size.
Now, what about implementations that don't allocate the max? That is, implementations that use the deallocate/reallocate approach, when assigning to a mutable record? Such an implementation would return the constrained size, even when the object is unconstrained.
The answer to these questions about mutable types should be Implementation Advice, since the exact semantics of Size is not defined by the language in these cases anyway. A hard requirement is uncalled for in this case (even for the SP Annex).
!appendix

!section 13.3(42)
!subject Object'Size
!reference RM95-13.3(42,43)
!from Keith Thompson 95-05-10
!reference as: 95-5141.a Keith Thompson 95-5-10>>
!discussion

The recommended level of support for the Size attribute of an
object implies that the following should be accepted:

    X: Integer;
    for X'Size use 1024;

Is this the intent?  If so, what should be done with the extra 922 bits
(if Integer'Size = 32)?  If X is passed as a parameter, must all 1024 bits
be copied?  (Presumably not, since the callee won't be expecting them.)

A possible implementation is to treat only the first 32 of the 1024 bits
as an Integer object, but then the other 922 bits are effectively not
part of X.  It seems more sensible to reject the size clause.  I see
little point in allowing a 'Size for an integer object to exceed the
largest size of any integer type.

Suggestion: for elementary types, the recommended level of support for
the Size attribute should not call for sizes larger than the largest
supported size for the class (discrete, float, access, etc.).

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

!section 13.3(42)
!subject Size clauses for objects specifying large sizes
!reference AI95-00051
!reference 13.3(42)
!from Tucker Taft 95-10-30
!reference 95-5373.g Tucker Taft 95-10-30>>
!discussion

This AI talks about base subtypes, which don't exist for
non-scalar types.  In general, when you start talking about
representation items, I find it is better to consider "integral" scalar types
(integer, enum, and fixed), floating point types, access types, array types,
and non-array composite types separately, rather than grouping everything
together.  If the right answer happens to be the same for each of
these distinct groups, great.  But don't be afraid to admit that
different rules are needed for different kinds of types.

As far as this AI, I think its recommendations are reasonable for
"integral" scalar subtypes.

For floating point and access subtypes, I don't think the implementation
needs to accept anything but a "confirming" Size clause.

For composite types, the Size clause on an object presumably just
specifies some amount of padding on allocation, but has no effect on any
other operations on the type, and hence is pretty trivial to support.
Even "block assignment" of a "padded" composite object should not
be affected, since assignment is really defined more in terms of
component-wise assignment, and clearly there are no additional components.
In particular, any gaps in the middle of a composite type don't need
to be assigned, compared, or whatever, as part of a predefined operation on
a composite object.  So clearly padding at the end can be ignored
for these operations as well.

Hence, for composite types, I would suggest that any size that is
a multiple of the storage unit, and is at least as big as the subtype
'Size, be accepted.  It need have no effect other than to add padding
at the end of the object.

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

!section 13.3(40)
!subject Size of Mutable Variables
!reference RM95-13.3(40)
!from Bob Duff
!reference 96-5496.a Robert A Duff 96-4-16>>
!discussion

What is the meaning of the Size attribute for an unconstrained variable
that is of a mutable type?  Consider:

    subtype Small_Natural is Natural range 0..100;
    type Mutable(Len: Small_Natural := 0) is
        record
            Chars: String(1..Len);
        end record;
    X: Mutable;

Suppose the implementation allocates the maximum possible size for X
(perhaps 104 bytes).  The "current size" of the value of X (i.e. the
"constrained size", with Len constrained to 0) is perhaps just 4 bytes
(for Len -- the Chars field is empty).  Should X'Size be the current
size (perhaps 4*8) or the maximum size (perhaps 104*8)?  The RM does not
answer this question.

After some discussion with Tucker and Robert Dewar, I believe the answer
should be the max size.  Here's why: Suppose we add a Size clause to the
above:

    for X'Size use 104*8; -- Specify the Size of the *object*.

Clearly, this will not be legal if 104*8 is less than the max possible
size.  By 13.1(17), a query of X'Size *must* now return 104*8.
13.1(17.a) gives an example of this.  So, in the case of a specified
Size (on the object), the query *cannot* return the current size.

To preserve the principle that confirming rep clauses shouldn't change
things, we must use the same rule even when there's *not* a Size clause.

Now, suppose we have a constrained object:

    subtype Mutable_3 is Mutable(Len => 3);
    Y: Mutable_3;
    Z: constant Mutable := (Len => 3, Chars => "abc");

Here, the compiler will not allocate the max size.  Y'Size and Z'Size
should clearly be the *constrained* Size -- the Size given that Len = 3.

Now, suppose we have a parameter:

    procedure Proc(Param1: Mutable; -- Constant; therefore constrained.
                   Param2: in out Mutable3; -- Constrained.
                   Param3: in out Mutable) is
    begin
        ...
    end Proc;

    Proc(X, X, X); -- Unconstrained actual parameters.
    Proc(Y, Y, Y); -- Constrained actual parameters.

Inside Proc, Param1'Size and Param2'Size should be the constrained size,
based on the value of the actual parameter's discriminant.  The
alternative would be to return the max size if the actual parameter
denotes an unconstrained object.  But that's not really reasonable from
an implementation point of view -- inside Proc, we don't know whether
the actual denotes an unconstrained object.

For Param3, however, we *do* know whether the actual is constrained or
unconstrained -- it is necessary to pass extra dope to implement the
'Constrained attribute.  Therefore, Param3'Size should be the max size,
or the constrained size, depending on the constrainedness of the actual
view.  (Note: I said "view" there because the actual could be another
formal -- we should care about the constrainedness of the actual *view*,
not the constrainedness of the actual *object*.)

Note: all aliased objects are constrained, so the parameter issue does
not come up for access values.  That is, Ptr.all'Size will clearly
always return the constrained size.

My conclusion from all this is that you have to view a declared object
as being a fixed-size container.  Thus, 'Size should return the max
size, if that's what was allocated.

Now, what about implementations that don't allocate the max?  That is,
implementations that use the deallocate/reallocate approach, when
assigning to a mutable record?  Presumably, such an implementation would
return the constrained size, even when the object is unconstrained.  One
might argue that we should make the rules the same for both kinds of
implementation.

However, in the example with the rep clause:

    for X'Size use 104*8; -- Specify the Size of the *object*.

it would seem that the RM forbids, or at least frowns upon, the
deallocate/reallocate implementation in this case.  In any case, the RM
requires X'Size to be 104*8.

Another point is that you can have aliased components of a record.  So
you can have pointers into the middle.  This implies that the
deallocate/reallocate approach is questionable anyway, in the general
case.  (In Ada 83, the same problem occurs when you rename a component.
One Ada 83 compiler, in fact, had exactly this bug -- renaming was
implemented as a pointer to the component, and a size-changing
assignment to the outer record caused the pointer to dangle.  Here, I'm
not talking about a discriminant-dependent component, whose renaming is
illegal -- just a regular component declared before the variant part.
You could get around this for renaming, by implementing renaming
differently -- store a pointer to the beginning of the outermost object,
and an offset.  But that implementation is not reasonable for
access-to-components, because unlike renamings, access values can be
assigned, so you would have a rather severe distributed overhead.  It
seems to me we worried about this case during the 9X design, and we
asked the DR's what to do.  They said to make the rules about
access-to-component the same as those for renaming-of-component, which
essentially forbids the deallocate/reallocate implementation.)

If an implementation does choose the deallocate/reallocate
implementation (presumably just in those cases where it works), then it
should be free to return the constrained size for an unconstrained
object.

It seems to me that the answer to the above questions should, at most,
be Implementation Advice, saying that Size "should" be such-and-such in
these cases.  I don't think a hard requirement is called for in this
case (even for the SP Annex).

- Bob

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

!section 13.3(40)
!subject Size of Mutable Variables
!reference RM95-13.3(40)
!reference 96-5496.a Bob Duff 96-4-16
!from Randy Brukardt (RR Software)
!reference 96-5502.a rbrukardt@BIX.com 96-4-20>>
!discussion

Most of the referenced message is confused, to say the least, about the
ways that various implementation models work.

>What is the meaning of the Size attribute for an unconstrained variable
>that is of a mutable type?  Consider:
>
>    subtype Small_Natural is Natural range 0..100;
>    type Mutable(Len: Small_Natural := 0) is
>        record
>            Chars: String(1..Len);
>        end record;
>    X: Mutable;
>
>Suppose the implementation allocates the maximum possible size for X
>(perhaps 104 bytes).  The "current size" of the value of X (i.e. the
>"constrained size", with Len constrained to 0) is perhaps just 4 bytes
>(for Len -- the Chars field is empty).  Should X'Size be the current
>size (perhaps 4*8) or the maximum size (perhaps 104*8)?  The RM does not
>answer this question.

Neither does Ada 83.  We assumed (for some reason which is no longer obvious),
we believed it is the current size.

>After some discussion with Tucker and Robert Dewar, I believe the answer
>should be the max size.  Here's why: Suppose we add a Size clause to the
>above:
>
>    for X'Size use 104*8; -- Specify the Size of the *object*.
>
>Clearly, this will not be legal if 104*8 is less than the max possible
>size.  By 13.1(17), a query of X'Size *must* now return 104*8.
>13.1(17.a) gives an example of this.  So, in the case of a specified
>Size (on the object), the query *cannot* return the current size.

That makes sense.

>To preserve the principle that confirming rep clauses shouldn't change
>things, we must use the same rule even when there's *not* a Size clause.

OK.

>Now, suppose we have a constrained object:
>
>    subtype Mutable_3 is Mutable(Len => 3);
>    Y: Mutable_3;
>    Z: constant Mutable := (Len => 3, Chars => "abc");
>
>Here, the compiler will not allocate the max size.  Y'Size and Z'Size
>should clearly be the *constrained* Size -- the Size given that Len = 3.

Well, that depends on the compiler.  I cannot imagine a situation where our
compiler would allocate record subtypes differently than the base type, even
if we adopted the 'max. size' implementation approach in some cases.

> ....
>
>My conclusion from all this is that you have to view a declared object
>as being a fixed-size container.  Thus, 'Size should return the max
>size, if that's what was allocated.

My first reaction to this statement is that it is first sensible statement
I've seen about 'Size in the entire 15 years I've been working with Ada.
OK, there must have been one other at some point.  :-)

This IS the model that our compiler has ALWAYS used.  For all objects.  For
all components.  For EVERYTHING.

>Now, what about implementations that don't allocate the max?  That is,
>implementations that use the deallocate/reallocate approach, when
>assigning to a mutable record?  Presumably, such an implementation would
>return the constrained size, even when the object is unconstrained.

No, it would return the size of the container.  In Ada 83, it appeared to
me that returning the constrained size was intended.  However, Ada 95 says
(13.3(56)) that the size of the container is returned, not including the
indirectly accessed space.  I would find it very strange that subtypes would
work one way, and objects would work the other.  And it wouldn't make any
sense, either.  For our current implementation, that would be 12*8.

>One might argue that we should make the rules the same for both kinds of
>implementation.

I think that the proposed solution IS the same for both kinds of implementation.

>However, in the example with the rep clause:
>
>    for X'Size use 104*8; -- Specify the Size of the *object*.
>
>it would seem that the RM forbids, or at least frowns upon, the
>deallocate/reallocate implementation in this case.  In any case, the RM
>requires X'Size to be 104*8.

I don't see any forbidding of a deallocate/reallocate implementation here.
I agree that X'Size is 104*8.  We will happly give your your 104 bytes, but
of course we would only use the first 12.  The other 92 would just be ignored.

>Another point is that you can have aliased components of a record.  So
>you can have pointers into the middle.  This implies that the
>deallocate/reallocate approach is questionable anyway, in the general
>case.  (In Ada 83, the same problem occurs when you rename a component.
>One Ada 83 compiler, in fact, had exactly this bug -- renaming was
>implemented as a pointer to the component, and a size-changing
>assignment to the outer record caused the pointer to dangle.  Here, I'm
>not talking about a discriminant-dependent component, whose renaming is
>illegal -- just a regular component declared before the variant part.
>You could get around this for renaming, by implementing renaming
>differently -- store a pointer to the beginning of the outermost object,
>and an offset.  But that implementation is not reasonable for
>access-to-components, because unlike renamings, access values can be
>assigned, so you would have a rather severe distributed overhead.  It
>seems to me we worried about this case during the 9X design, and we
>asked the DR's what to do.  They said to make the rules about
>access-to-component the same as those for renaming-of-component, which
>essentially forbids the deallocate/reallocate implementation.)

I have no clue as to what you are talking about here.  We had this discussion
during the development of Ada 95.  I can assure you that if the rules would
have forbidden the deallocate/reallocate implementation, I would have screamed
bloody murder!  No, the aliased component rules do not cause any problems
for deallocate/reallocate model.  Obviously that compiler you are thinking of
had a severe bug that had nothing whatsoever to do with the implementation
model.

Consider:
Declare
    type Mutable_Again(Len: Small_Natural := 0) is
        record
            Chars: Aliased String(1..Len);
            Counter : Aliased Integer := 0;
        end record;
    X: Mutable_Again;
    X3: Mutable_Again(3);
    Type P_Int Is Access All Integer;
    P : P_Int;
Begin
    P := X.Counter'Access;
    X := (3, "ABC", 10);
    Put (P.All); -- Will print 10.
End;

Our implementation assigns ALL object addresses and component offsets statically.
In this case, for the Pentium machine, we would have:
        X.Len'Offset = 0;
        X.Chars'Offset = 2;
        X.Counter'Offset = 12;
When we assign the pointer, we will store X'Address + 12.
When X is mutated, Chars'Data will be deallocated, and a new one allocated.
That will have no effect on the offset of Counter, so that X'Address + 12
still points at the component Counter, and there is no problem.

Of course, X.Chars'Access would change during this assignment, but it of
course is discriminant dependent, so the 'Access is illegal.
X3.Chars'Access can be taken, but since the type is not mutable, the
item Chars'Data will never be deallocated/reallocated, so again there is no
problem.

>If an implementation does choose the deallocate/reallocate
>implementation (presumably just in those cases where it works), then it
>should be free to return the constrained size for an unconstrained
>object.

As above, it always works.  At least ours does.  Secondly, I don't think we
want it to return the constrained size.  I think we want it to return the
subtype size here, that is Mutable'Size.

>It seems to me that the answer to the above questions should, at most,
>be Implementation Advice, saying that Size "should" be such-and-such in
>these cases.  I don't think a hard requirement is called for in this
>case (even for the SP Annex).

OK by me.  But consider the above first.

>- Bob

        Randy.

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

!section 13.3(40)
!subject Size of Mutable Variables
!reference RM95-13.3(40)
!reference 96-5496.a Bob Duff 96-4-16
!reference 96-5502.a rbrukardt@BIX.com 96-4-20
!from Bob Duff
!reference 96-5505.a Robert A Duff 96-4-21>>
!discussion

> Most of the referenced message is confused, to say the least, about the
> ways that various implementation models work.

> >    subtype Mutable_3 is Mutable(Len => 3);
> >    Y: Mutable_3;
> >    Z: constant Mutable := (Len => 3, Chars => "abc");
> >
> >Here, the compiler will not allocate the max size.  Y'Size and Z'Size
> >should clearly be the *constrained* Size -- the Size given that Len = 3.
>
> Well, that depends on the compiler.  I cannot imagine a situation where our
> compiler would allocate record subtypes differently than the base type, even
> if we adopted the 'max. size' implementation approach in some cases.

IMHO such a compiler is pretty badly broken.  It seems essential to me
that you allocate constrained objects using the constrained size.  I
suppose the RM doesn't say that, but neither does it say you can't
allocate 2**32 bits for an integer variable.

> My first reaction to this statement is that it is first sensible statement
> I've seen about 'Size in the entire 15 years I've been working with Ada.

:-)

> I have no clue as to what you are talking about here.

Sorry, I didn't define what I meant by the deallocate/reallocate
approach.  There are actually (at least) two deallocate/reallocate
approaches.  The one *I* was talking about, is where the whole object is
deallocated and then reallocated on assignment.  The compiler I was
talking about had a bug that is *directly* *caused* by this
implementation approach.

You, on the other hand, are talking about deallocating/reallocating just
the discriminant-dependent component.  Yes, I agree that this approach
works fine in the presence of aliased objects and renaming.  (It's a
rather unusual approach, though, is it not?  I was under the impression
that *most* compilers always allocate a single contiguous block of
storage for each object.)

>....We had this discussion during the development of Ada 95.  I can
> assure you that if the rules would have forbidden the
> deallocate/reallocate implementation, I would have screamed bloody
> murder!

Didn't you do just that, numerous times?  ;-) ;-)

Yes, *your* deallocate/reallocate approach is not broken by the Ada 95
rules.  Not to worry.

>...  No, the aliased component rules do not cause any problems
> for deallocate/reallocate model.  Obviously that compiler you are thinking of
> had a severe bug that had nothing whatsoever to do with the implementation
> model.

> As above, it always works.  At least ours does.  Secondly, I don't think we
> want it to return the constrained size.  I think we want it to return the
> subtype size here, that is Mutable'Size.

Actually, I don't think it matters at all what 'Size returns -- if the
object is not a single contiguous region of storage, then the 'Size
attribute seems useless, anyway.

- Bob

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

!section 13.3(40)
!subject Size of Mutable Variables
!reference RM95-13.3(40)
!reference 96-5496.a Bob Duff 96-4-16
!reference 96-5502.a rbrukardt@BIX.com 96-4-20
!reference 96-5505.a Robert A Duff 96-4-21
!from Randy Brukardt
!reference 96-5506.a Ian Goldberg  96-4-23>>
!discussion

>> Well, that depends on the compiler.  I cannot imagine a situation =
where our
>> compiler would allocate record subtypes differently than the base =
type, even
>> if we adopted the 'max. size' implementation approach in some cases.

>IMHO such a compiler is pretty badly broken.  It seems essential to me
>that you allocate constrained objects using the constrained size.  I
>suppose the RM doesn't say that, but neither does it say you can't
>allocate 2**32 bits for an integer variable.

I slightly misspoke here.  I was thinking more about layout than size, =
and it is possible to have a constrained record with the same layout as =
the unconstrained parent, but with a different size.

My real concern here is that we don't adopt a set of language rules =
which encourage compilers to lie about what they did.  (This is common =
in Ada 83 compilers for 'Size, I believe)  That does not benefit the =
users of the language
and simply makes more work for the implementors.  My strong desire when =
it comes to 'Size for objects is to simply return the size allocated, =
whatever that was -- and if the size is specified, to allocate that =
size.

>Sorry, I didn't define what I meant by the deallocate/reallocate
>approach.  There are actually (at least) two deallocate/reallocate
>approaches.  The one *I* was talking about, is where the whole object =
is
>deallocated and then reallocated on assignment.  The compiler I was
>talking about had a bug that is *directly* *caused* by this
>implementation approach.

>You, on the other hand, are talking about deallocating/reallocating =
just
>the discriminant-dependent component.  Yes, I agree that this approach
>works fine in the presence of aliased objects and renaming.  (It's a
>rather unusual approach, though, is it not?  I was under the impression
>that *most* compilers always allocate a single contiguous block of
>storage for each object.)

I don't know if it is unusual, but certainly it makes more sense than =
the one you describe, even for Ada 83.  (And, as you say, the approach =
you describe is likely wrong for Ada 95).  Besides being much more =
user-friendly ('Access and 'Address work, mutable subtypes don't need =
their size limited), our
approach does not have any extra cost over the one you describe in the =
most common cases (that is, a single mutable component, when the entire =
type is used as a variable or component).  And it's much easier to write =
the compiler and generate good code when component offsets are always =
static.  The only real downside is with I/O of these types, but that is =
easily handled with attributes similar to the stream attributes (which =
is why I wanted the stream attributes to apply to Sequential_IO and =
Direct_IO -- the current situation is that we end up with 4 sets of =
them.)

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

!section 13.3(42)
!subject Size and Alignment of (aliased) objects
!reference AI95-00051/02
!from Erhard Ploedereder 96-07-27
!reference 96-5625.a Erhard Ploedereder  96-7-26>>
!discussion

AI-00051/02 states (among other things):
"For an aliased object, the implementation need not support a Size clause
 that is different from what the implementation would have chosen by
 default."

I do not understand the rationale for "need not", which tends to imply
"tough, but possible". Short of runtime size descriptors with each value
(surely not an implementation model for scalar types), this is a "can not"
and therefore should be a "must not" in language rules. (I, for one, would
not know how to implement the access via an access type, when the size of
the designated scalar subtype is not guaranteed to be equal to the size of the
designated object.)

The sentence above does not cover the case of aliased components with
component_clauses forcing a non-default size.

The AI states further:
"For an aliased object, the implementation need not support an Alignment
clause that is less strict than what the implementation would have
chosen by default."

The same argument as given above applies. This should be a "must not" rule
and the transitive alignment effect of component_clauses within
records with alignment clauses should be added.

Going right along....:
"For an aliased object, if an Address clause or a pragma Import is given,
the implementation need not support an Alignment clause that is stricter
than what the implementation would have chosen by default."

There is no !discussion of why this statement is made. Why is there a
connection between pragma Import or an Address clause and this advice
regarding stricter alignment.  If there is such a rationale, why doesn't the
sentence above extend component-"claused" components of records with address
clauses ?  Many questions, but the AI doesn't answer them.

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

!section 13.3(42)
!subject Size and Alignment of (aliased) objects
!reference AI95-00051/02
!reference as: 96-5625.a Erhard Ploedereder  96-7-26>>
!from Robert I. Eachus
!reference 96-5627.a Robert I. Eachus 96-7-29>>
!discussion

 > I do not understand the rationale for "need not", which tends to
 > imply "tough, but possible". Short of runtime size descriptors
 > with each value (surely not an implementation model for scalar
 > types), this is a "can not" and therefore should be a "must not"
 > in language rules. (I, for one, would not know how to implement
 > the access via an access type, when the size of the designated
 > scalar subtype is not guaranteed to be equal to the size of the
 > designated object.)

   If the scope of the type is entirely within a single compilation,
it can be done without descriptors.  So I think tough, but possible in
some circumstances is a legitimate rule, and there is no reason to
forbid something in all cases just because it is impossible in some.

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

From: 	Robert Dewar
Sent: 	Monday, March 22, 1999 3:19 PM

<<4. For a non-aliased object, the implementation need not support an
Alignment clause unless the Alignment evenly divides the size (in
storage elements) of the object.
>>

I do not like the terminology of evenly divides. It is much clearer
to say that x is an exact multiple of y.

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



Questions? Ask the ACAA Technical Agent