Version 1.1 of ais/ai-00246.txt
!standard 4.06 (12) 00-10-31 AI95-00246/01
!class binding interpretation 00-10-31
!status work item 00-10-31
!status received 00-10-31
!priority Medium
!difficulty Medium
!subject
!summary
A view conversion between two arrays that do not have a common ancestor is
illegal if their component type is has a private or visibly
by-reference subcomponent.
!question
Consider the following example:
type T is limited null record; --
type A1 is array (1..2) of T;
for A1'Component_Size use 8;
type A2 is array (1..2) of T;
for A2'Component_Size use 32;
procedure P (X : A1) is
begin
...
end P;
Y : A2 := ...;
...
P (A1 (Y)); --
Inside of P, it seems legitimate for the generated code to assume that the
component size is 8, e.g. in indexing the array. However, the view conversion
will pass an array with a different component size. This is very inefficient
to implement. Is this the intent? (No.)
!recommendation
(See summary.)
!wording
(See corrigendum.)
!discussion
Clearly, there is no practical way to generate code for the view conversion.
Since the type in question is by-reference, the implementation cannot make a
copy in order to get the appropriate representation.
Thus, the program needs to be made illegal. This could be accomplished by
making the representation clauses illegal, or by making the view conversion
illegal.
Making representation items on by-reference types illegal is not very
attractive. Such a rule would prevent the use of convention pragmas along with
other items. Moreover, view conversions of untagged type is rare; but this
solution would eliminate a potentially useful capability in order to eliminate
a problem with a rarely used feature.
Thus, we make the view conversion illegal.
The rule we've adopted is
In a view conversion, if the target type and the operand type do not
have a common ancestor, then the component subtype shall not have a private
or visibly by-reference subcomponent.
This rule has the benefit of not breaking privateness of private types, nor
to define an "assume-the-worst" rule for generics. This holds to the contract
model; the legality of a conversion does not depend on the full definition of
a type. It means that effectively we're using an assume-the-worst rule for
all private types.
It might appear that this sort of problem would occur for other untagged
composite view conversions. (Such conversions must be between derived types.)
However, 13.1(10) prevents these sorts of problems for type-related aspects of
by-reference derived types. So we don't need a rule to handle them. AARM
13.1(10.b) explains that this rule exists precisely to prevent this sort of
problem.
The model for subtype-related attributes is that implementations do not allow
the specification of 'Size and/or 'Alignment values that would cause problems
accessing reference parameters. Thus, no rule is needed to handle this case.
An alternative rule was considered:
In a view conversion, if the target type and the operand type do not
have a common ancestor and are a by-reference type, then neither type may
have a representation item. In addition to the normal places that legality
rules apply, this also applies in the private part of a generic unit. This
rule is checked in an assume-the-worst manner in generic bodies.
This rule was rejected mainly because of concerns over determining whether a
type is by-reference. In particular, that cannot be determined until the type
is frozen. However, it is not possible in Ada 95 for an array view conversion
to occur before the type is frozen. (An untagged view conversion requires an
in out parameter, but that cannot be used in a function call.)
!corrigendum 4.6(12)
Replace the paragraph:
- The component subtypes shall statically match; and
- In a view conversion, the target type and the operand type shall both
or neither have aliased components.
by:
- The component subtypes shall statically match; and
- In a view conversion, the target type and the operand type shall both
or neither have aliased components; and
- In a view conversion, if the target type and the operand type do not
have a common ancestor, then the component subtype shall not have a private or
visibly by-reference subcomponent.
!ACATS test
Create a B-Test which checks that the new rule is enforced.
!appendix
From: Pascal Leroy [pleroy@RATIONAL.COM]
Sent: Wednesday, October 18, 2000 7:04 AM
> If there is a problem in the RM mandating rep clauses that we are not
> sure should be accepted in all compilers, then we should fix this.
> It is preemptive evidence of such a situation if a major vendor is
> not implementing something that is required by the RM.
We have encountered many problems with chapter 13. Let me just take one
example that has nothing to do with generics. We reject any non-confirming
Component_Size clause on an array of a by-reference type. Why? Because we
do not know how to implement view conversion of arrays in this case. Well,
we know how to implement it, but that would be insanely inefficient. I
suppose that you would see this as a violation of the recommended level of
support, but sorry, I cannot feel guilty.
And yes, I should have opened AIs for these issues, but given the attention
that AIs have gotten lately, I cannot get too motivated...
> Pascal's point of view is essentially saying that implementors are
> completely free to ignore RM C.2(2) and that is going MUCH too far.
Not at all. Pascal is saying that the recommended level of support in
chapter 13 is subject to the "impossible or impractical" rule of RM95
1.1.3(4). Of course, the "impossible or impractical" rule is a can of worms
that can lead to endless discussions; that's why I am inclined to let the
market decide.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 7:15 AM
<<We have encountered many problems with chapter 13. Let me just take one
example that has nothing to do with generics. We reject any non-confirming
Component_Size clause on an array of a by-reference type. Why? Because we
do not know how to implement view conversion of arrays in this case. Well,
we know how to implement it, but that would be insanely inefficient. I
suppose that you would see this as a violation of the recommended level of
support, but sorry, I cannot feel guilty.>>
Can you give a brief example here of where this would cause inefficiency?
<<Not at all. Pascal is saying that the recommended level of support in
chapter 13 is subject to the "impossible or impractical" rule of RM95
1.1.3(4). Of course, the "impossible or impractical" rule is a can of worms
that can lead to endless discussions; that's why I am inclined to let the
market decide.>>
That's an abuse of 1.1.3(4). (I can speak with some historical authority
here, since this is just AI 325 :-)
If there is ever a case where something would be impsosible or impractical
for all targets for a reasonable implementation approach, or for all
implementation approaches we can think of, then 1.1.3(4) definitely does
NOT apply. This is specigfically intended for target dependent or other
special situations.
If we find a case where there is NO reasonable implementation, then it is
wrong to appeal to 1.1.3(4), instead we should identify this as a bug
that should be fixed.
I actually think that fixing problems of this kind is a whole lot more
useful than many of the other esoteric AI's the ARG has worked on :-)
And by the way, I do not think it is the case that AI325 or 1.1.3(4) is
a can of worms. We really have seen almost no cases of attempted abuse
of this quite reasonable rule (analogous to the general interruption
rule in Algol68). But it is important to be vigilant and avoid abuse,
and the claim that a feature in the language is fundamentally too
inefficient to implement and therefore 1.1.3(4) applies is an abuse :-)
All large real programs are full of representation clauses, if we wave our
hands and say rep clauses are completely implementation dependent, we are
saying goodbye to portability on too large a scale. As the person who
helped design and implement the ACVC 1.10 tests that finally demanded
some level of portability in rep clauses, this is something that I
feel strongly about. And after all, it is clear that the 95 RM feel
strongly too, since it put a lot of effort into trying to clearly
define this.
(Erhard, I trust these messages are more in the style of what you
think should happen on this list :-)
****************************************************************
From: Pascal Leroy
Sent: Wednesday, October 18, 2000 7:47 AM
Here is an example:
type T is limited null record; -- by-reference
type A1 is array (1..2) of T;
for A1'Component_Size use 8;
type A2 is array (1..2) of T;
for A2'Component_Size use 32;
procedure P (X : A1) is
begin
... -- Here it seems legitimate for the generated code
-- to assume that the component size is 8, e.g. in indexing the
array.
end;
Y : A2 := ...;
...
P (A1 (Y)); -- A view conversion, passed by-reference.
Y has 32-bit components, but the generated code for P assumes that its
parameter has 8-bit components, so it's unlikely to work. The only way out
of this conundrum would be to pass to P (as an extra parameter or as some
kind of dope stored with the array) the actual component size, and have the
generated code use that value. It would of course be complex and costly,
not to mention that it would impose a distributed overhead to deal with the
unlikely case where someone plays games with the component size.
The ironic twist is that this overhead would be required to comply with
(Robert's interpretation of) annex C, but precisely users of annex C is
likely to be demanding in terms of performance...
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 8:00 AM
The extra parameter is really out of the question, so I agree this is
a hole that needs plugging.
<<The ironic twist is that this overhead would be required to comply with
(Robert's interpretation of) annex C, but precisely users of annex C is
likely to be demanding in terms of performance...>>
Well I am not sure there is any interpretation issue here. If I understand
this right, this is clearly a mistake. This is quite analogous to the
exceptions that have to be made for aliased objects to ensure that pointers
to them are interpretable.
I tried running this exact example:
with Text_IO; use Text_IO;
procedure a is
type T is limited record
x : integer := 3;
end record;
type A1 is array (1..2) of T;
for A1'Component_Size use 8;
type A2 is array (1..2) of T;
for A2'Component_Size use 32;
procedure P (X : A1) is
begin
for J in X'Range loop
Put_Line (X (J).x'Img);
end loop;
end;
Y : A2;
begin
P (A1 (Y)); -- A view conversion, passed by-reference.
end;
-----
GNAT rejects the rep clauses, although the message is not exactly clear :-) :-)
a.adb:23:07: left hand of assignment must not be limited type
this complains about the call, so it is not really a rejection of the rep
clause, but a plain bug.
I agree there is no obvious implementation here, I think we have to change
GNAT to reject the rep clause as you suggest.
But I am surprised you do not think this is something that needs fixing
in the language!
****************************************************************
From: Pascal Leroy
Sent: Wednesday, October 18, 2000 8:40 AM
> But I am surprised you do not think this is something that needs fixing
> in the language!
Well, you're right. I guess I have taken the detestable habit of thinking
that I could fix chapter 13 "by myself" :-)
Note that this is not a single hole, it's an entire family of holes.
First, there is a similar problem with alignment. If you write alignment
clauses that specify 4-byte alignment for A2 and 1-byte alignment for A2,
then it is fine for the generated code of P to take advantage of the fact
that its parameter is 4-byte aligned, thereby resulting in better code.
However, when P is passed Y, which is only 1-byte aligned, bad things happen
(at least on some processors). The only implementation that I can think of
would have to look at the least significant bits of the address of its
parameter, but again that would be unreasonable.
Then, there are additional problems with other types and with objects:
1 - Untagged derived types: again there are issues with view conversions, so
the size and alignment of the parent and the derived type must agree.
2 - Record types: a component may be of a by-reference type, in which case a
component clause for that component must be confirming in terms of size and
alignment.
3 - Objects of a by-reference type: the object must fulfill the promises
made by the type, so the alignment of an object must be stricter than that
of the type and the size must be confirming.
I realize that the above statements are rather vague, and would need to be
clarified with example. I'm only dumping the problems I remember. There
may be others. In essence, by-reference types that can be view-converted to
each other must obey some type of "contract", in the sense that they must
all have more-or-less the same representation. Similarly, objects must
comply with the "contract" for the type.
****************************************************************
From: Robert A Duff
Sent: Wednesday, October 18, 2000 9:43 AM
> Well, you're right. I guess I have taken the detestable habit of thinking
> that I could fix chapter 13 "by myself" :-)
I tried that once ("fix" chap 13).
Robert jumped all over me for it, too. ;-)
> 2 - Record types: a component may be of a by-reference type, in which case a
> component clause for that component must be confirming in terms of size and
> alignment.
Isn't this one covered by 13.1(10)? See also AARM para 10.b.
13.1(24-24.c) also seems relevant to this issue in general.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 9:51 AM
As I say, this seems very reminiscent of the exceptions we need to make
in the aliased case, and the reasons are very much analogous. I think
all of these probably fall into a single issue, since it is basically
one issue (the notion of "contract" for a type is a useful one here).
****************************************************************
From: Pascal Leroy
Sent: Wednesday, October 18, 2000 10:01 AM
> > 2 - Record types: a component may be of a by-reference type, in which case
> > a component clause for that component must be confirming in terms of size
> > and alignment.
>
> Isn't this one covered by 13.1(10)? See also AARM para 10.b.
I don't understand. 13.1(10) doesn't have anything to say about records
having a component of a by-reference type. Could you explain what you mean?
As for AARM 13.1(10.b), it claims that subtype-specific changes of
representation are cheap, and I believe that's the fallacy. If you have
generated code that assumes 4-byte alignment, passing a parameter which is
only 1-byte aligned is not going to be cheap.
> 13.1(24-24.c) also seems relevant to this issue in general.
It is relevant, but it is insufficiently stringent. It's not only that the
component must be addressable, it must be addressable in a way which is
consistent with all the view conversions in which it can participate. As I
said, there is a contract issue here; addressability is only one item in the
contract.
****************************************************************
From: Robert A Duff
Sent: Wednesday, October 18, 2000 10:52 AM
> I don't understand. 13.1(10) doesn't have anything to say about records
> having a component of a by-reference type. Could you explain what you mean?
I don't know. Maybe I quoted the wrong item on your list, or maybe I
was just confused. Anyway, you've certainly made the point that there
are some problems in this area.
> As for AARM 13.1(10.b), it claims that subtype-specific changes of
> representation are cheap, and I believe that's the fallacy.
No, that's not talking about by-reference. It's claiming that (by-copy)
conversions with subtype-specific changes are cheap, which is true.
Note that that part is talking about the Ada 83 rule ("The reason
... *was* ...") (emphasis added). And Ada 83 didn't have by-reference
types.
The problem here is that we just didn't think of these cases where
viewish type conversions and by-ref types conspire to make
implementation infeasible. As Robert points out, this is related to the
interactions between packing and aliased components and so forth.
****************************************************************
From: Jean-Pierre Rosen
Sent: Wednesday, October 18, 2000 11:47 AM
> I don't understand. 13.1(10) doesn't have anything to say about records
> having a component of a by-reference type. Could you explain what you mean?
A record with a subcomponent of a by-reference type is a by-reference
type. 6.2(8)
****************************************************************
From: Tucker Taft
Sent: Thursday, October 19, 2000 12:03 PM
Pascal Leroy wrote:
> I don't understand. 13.1(10) doesn't have anything to say about records
> having a component of a by-reference type. Could you explain what you mean?
If a record has a subcomponent of a
by-reference type, then the record as a whole is a
by-reference type (6.2(8)).
However, I agree that 13.1(10) is only talking about
derived types. You are talking about problems with
specifying *any* representation aspects for components
(or for types) of a by-reference type.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 11:04 AM
<<> As for AARM 13.1(10.b), it claims that subtype-specific changes of
> representation are cheap, and I believe that's the fallacy.>>
Bob said
<<No, that's not talking about by-reference>>
That's got to be wrong! The whole model here is that subtype specific
changes of representation must be cheap for by reference or the whole
mechanism of calling subprograms with reference parameters breaks if
there are derived types. Most certainly the understanding is that
subtype-specific changes of representation are cheap. That should be
true because
a) for size, in the case of things you would pass by reference, size can
do nothing more than add or subtract padding space at the end.
b) for alignment, you do not allow specification of alignments that are
smaller than usual in a way that would cause trouble (at least we don't :-)
So I think Pascal is right on the description of the change, wrong that it
is a fallacy.
****************************************************************
From: Erhard Ploedereder
Sent: Wednesday, October 18, 2000 12:43 PM
> type A1 is array (1..2) of T;
> for A1'Component_Size use 8;
> type A2 is array (1..2) of T;
> for A2'Component_Size use 32;
> Y : A2;
> begin
> P (A1 (Y)); -- A view conversion, passed by-reference.
> end;
Seems to me that this cannot possibly be a view conversion (this would
be semantic madness).
If legal at all, this MUST BE a value conversion by any sensible
language semantics (and I am not talking just Ada).
Is there really no rule in the RM, that view conversions cannot convert
between representationally different untagged subtypes ??? I looked and
couldn't find any. If that's true, THAT'S A BIG HOLE.
13.6. clearly should apply only to value conversions.
What remains to be answered is whether
a) the rule of what constitutes a view conversion -- 4.6(5) -- needs to
be amended for the second case with "and the source and target subtype
have equal representation (see 13)", and copy-in/copy_out conversions
prescribed otherwise, illegal for by-reference types and IN OUT
generic formal objects.
b) the rule for view conversions stays as is and a view conversion
among untagged types of different representation is made illegal.
Compatibility arguments (with Ada83) favor alternative a) .
Simplicity favors alternative b).
The generic formal type problem I would solve by an illegality rule.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 1:01 PM
<<Is there really no rule in the RM, that view conversions cannot convert
between representationally different untagged subtypes ??? I looked and
couldn't find any. If that's true, THAT'S A BIG HOLE.>>
I agree, but really if it is not a view conversion, then the conversion
should not be allowed at all in this context, given that it is a by reference
type. I would make this conversion illegal in this context.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 18, 2000 2:22 PM
We have to be careful here, given that tagged types are all by-reference,
and ordinary conversions are value conversions. There is not any (current)
rule prohibiting value conversions of by-reference types, and we have to be
careful if we introduce one to avoid a serious incompatibility.
****************************************************************
From: Erhard Ploedereder
Sent: Wednesday, October 18, 2000 1:28 PM
> I agree, but really if it is not a view conversion, then the conversion
> should not be allowed at all in this context, given that it is a by
> reference type. I would make this conversion illegal in this context.
Indeed. And that's what I was saying, too. But the problem is not only with
by-reference types, but a more general problem (with the standard) even if T
is not limited.
The RM right now doesn't seem to allow to implement such a call situation by
value conversions at all for non-limited parameter types (and that would be
an incompatibility with Ada83).
You cannot possibly blame it on the rep.specs and make them illegal
somehow. It's the view conversion semantics that's at fault.
(Plus, it's yet another nail in the coffin of shared generics
because of generic formal IN OUT objects, whose semantics prescribe a view
conversion.)
****************************************************************
From: Erhard Ploedereder
Sent: Wednesday, October 18, 2000 1:38 PM
Postscript:
> The RM right now doesn't seem to allow to implement such a call situation by
> value conversions at all for non-limited parameter types (and that would be
> an incompatibility with Ada83).
Sorry, I take that back. (It's been a long day.) 6.2 is of course the place.
But the issue on generic IN OUT formal objects remains, I believe.
(Sure, it's easily implemented matching the intent, except for shared
generics. But the standard mumbles about a view conversion there and
that just ain't right.)
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 18, 2000 11:59 AM
Since Pascal seems unwilling to initiate the AI, I'll do it, in order that
this e-mail exchange has a place to be stored for future reference.
Let me try to clarify the issue a bit (or perhaps muddy the waters some
more).
It seems that the problem occurs only if the type has aliased or
by-reference subcomponents (or is such a type). Clearly, if that is not
true, we simply have to use copy-in, copy-out for parameter passing in the
case that the representations don't match in some significant (to the
generated code) way. That is already mandated for elementary types, and is
not a big deal for other types. (As I understand it, the reason that doing
such conversions implictily is frowned about is accuracy concerns, but that
does not apply here, as the conversions in question are explicit.) (Based on
the error message Robert reported, it seems pretty clear that that is
exactly what GNAT is doing.)
However, in the case of aliased or by-reference subcomponents, we cannot
copy the item without violating the properties of the component. Thus, if we
have a type T that contains aliased or by-reference subcomponents, then for
all types that T is view convertible to, the value of any representation
property significant to the generated code must be the same.
What we need to do, therefore, is amend the "Recommended Level of Support"
for representation items to insure such cases are excluded. (After all,
these recommendations are required by Annex C.) We don't want to insist that
implementations not support this (because implementations are always allowed
to go beyond the recommended level of support), but we must not mandate it.
Is this a correct summary? I've purposely left the question as to what
representation properties are affected blank, because I wanted to summarize
the big issue first.
****************************************************************
From: Pascal Leroy
Sent: Wednesday, October 18, 2000 2:55 PM
I agree with the above summary (well, it's rather vague so I'll need to see
the details, but the general direction is fine).
****************************************************************
From: Tucker Taft
Sent: Wednesday, October 18, 2000 2:57 PM
> However, in the case of aliased or by-reference subcomponents, we cannot
> copy the item without violating the properties of the component. Thus, if we
> have a type T that contains aliased or by-reference subcomponents, then for
> all types that T is view convertible to, the value of any representation
> property significant to the generated code must be the same.
An alternative is to disallow view conversions in certain
cases. Remember that for untagged types, view conversions
only appear when an actual is a conversion, and the mode
is [in] out. This is not a highly used feature of
the language, I would guess. Disallowing its use
for by-reference types (even if they happen to have the
same representation) might not be a major incompatibility.
Disallowing certain rep clauses on by-reference types might
be a bigger incompatibility.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 1:55 PM
<<What we need to do, therefore, is amend the "Recommended Level of Support"
for representation items to insure such cases are excluded. (After all,
these recommendations are required by Annex C.) We don't want to insist that
implementations not support this (because implementations are always allowed
to go beyond the recommended level of support), but we must not mandate it.
Is this a correct summary? I've purposely left the question as to what
representation properties are affected blank, because I wanted to summarize
the big issue first.>>
I am concerned that prohibiting useful rep clauses for by reference types
just so that such conversions can work is far too draconian. I would
prefer a solution that just makes the conversions invalid.
****************************************************************
From: Pascal Leroy
Sent: Wednesday, October 18, 2000 3:01 PM
Nobody talked about "prohibiting useful rep clauses". The point is to "not
mandate them" if the implementation doesn't know how to support them
efficiently.
Considering that view conversions occur everywhere in OOP (because of
conversions to the parent type) I would be extremely concerned that changing
anything in this area would break existing code...
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 3:10 PM
Well it seems like you want to solve this by disallowing the rep clause.
I would prefer to be more permissive by allowing the rep clauses, but
then disallowing the bogus conversion.
You can't just take the position that I can allow the rep clauses if and only
if I allow the conversion because
a) that makes the old mistake of saying you can't offer A, only A and B,
but you can offer neither
b) that *does* amount to prohibiting useful rep clauses in practice if
not in theory.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 2:00 PM
Actually our attempt to find out what a view conversion was proved a bit
surprising, it seems like a lot of conversions are defined as view
conversions in a surprising manner, but perhaps we are missing something.
****************************************************************
From: Pascal Leroy
Sent: Wednesday, October 18, 2000 2:52 PM
> > type A1 is array (1..2) of T;
> > for A1'Component_Size use 8;
>
> > type A2 is array (1..2) of T;
> > for A2'Component_Size use 32;
>
> > Y : A2;
>
> > begin
> > P (A1 (Y)); -- A view conversion, passed by-reference.
> > end;
>
> Seems to me that this cannot possibly be a view conversion (this would
> be semantic madness).
>
> If legal at all, this MUST BE a value conversion by any sensible
> language semantics (and I am not talking just Ada).
Well, it cannot be a value conversion in the general case, because T could
be one of these things that you cannot copy (eg a record with a
self-referential access component).
> Is there really no rule in the RM, that view conversions cannot convert
> between representationally different untagged subtypes ??? I looked and
> couldn't find any. If that's true, THAT'S A BIG HOLE.
There is a meta-rule of Ada that the static semantics don't depend on the
representation aspects, just on the logical properties of types (this rule
was very prominently stated in the rationale for Ada 83). Hopefully you are
not suggesting to break it?! We have had a similar discussion circa AD 1995
about the meaning of "statically matching subtypes", and as far as I recall,
Robert was arguing that subtypes don't match if they have different
representations. He lost the argument at the time, but beware, he's
fighting back :-)
I entirely disagree with your proposed fix. The component size clause is
really what's causing trouble, an implementation must be allowed to reject
it, period. Changing the rules about view conversions (and generic in out)
at this point doesn't make sense to me.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 3:20 PM
Perhaps we should allow rejection, but in practice Pascal is trying
to *insist* that it be rejected (his point that you can allow it if
you figure out how is bogus, since we know there is no good implementation
model that would allow this conversion).
Once again, Pascal is saying
1. My view is that you are allowed to accept the rep clause ONLY if
you also allow the conversion. But you can reject both as we have
chosen to do.
2. Even though an implementation that accepts the rep clauses byut
disallows the conversion is clearly more powerful than one that allows
neither, such an implementation should not be tolerated.
I really dislike this "nothing is better than something" attitude, especially
when the something is clearly useful.
****************************************************************
From: Stephen Michell
Sent: Wednesday, October 18, 2000 2:15 PM
Seems to me that this problem is just other examples of AI-168. AI-168 started
with Arrays, but the underlying issue is the disconnect between objects with
representations different than one would expect from it's type as expressed in,
say, a subprogram parameter.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 18, 2000 3:43 PM
Steve said:
> Seems to me that this problem is just other examples of AI-168. AI-168 started
> with Arrays, but the underlying issue is the disconnect between objects with
> representations different than one would expect from it's type as expressed
> in, say, a subprogram parameter.
AI-168 is in the corrigendum, and the solution to the array problem was to
disallow certain view conversions.
Pascal said:
> There is a meta-rule of Ada that the static semantics don't depend on
> the representation aspects, just on the logical properties of types
> (this rule was very prominently stated in the rationale for Ada 83).
> Hopefully you are not suggesting to break it?!
This seems to be a powerful argument for Pascal's position, except that he
then undermines it...
> We have had a similar discussion circa AD 1995 about the meaning of
> "statically matching subtypes", and as far as I recall,
> Robert was arguing that subtypes don't match if they have different
> representations. He lost the argument at the time, but beware, he's
> fighting back :-)
I remember the argument, but I would be very wary of claiming who won or
lost. This is AI-108, which is still open. That is, it never really got
resolved. Indeed, its pretty much impossible to implement pointer
conversions if static matching does not imply identical representations
(that's why those things require static matching in the first place, because
one of the UI teams (mine) reported problems with 'Access on arrays with
non-matching constraints (such as unconstrained array parameters).
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 3:23 AM
> Seems to me that this problem is just other examples of AI-168. AI-168 started
> with Arrays, but the underlying issue is the disconnect between objects with
> representations different than one would expect from it's type as expressed in ,
> say, a subprogram parameter.
That's related, but not identical. AI-168 had to do with aliased-ness of
components, which is a logical property of the type, so we just fixed it by
adding a new legality rule. This didn't create contract model problems
because the aliased-ness of the components is part of the contract. And it
didn't require to look at the representation.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 4:04 PM
<<I remember the argument, but I would be very wary of claiming who won or
lost. This is AI-108, which is still open. That is, it never really got
resolved. Indeed, its pretty much impossible to implement pointer
conversions if static matching does not imply identical representations
(that's why those things require static matching in the first place, because
one of the UI teams (mine) reported problems with 'Access on arrays with
non-matching constraints (such as unconstrained array parameters).
>>
Right, as I said earlier, to me the issue of ensuring that you can deal
with what's at the end of an access value is *VERY* similar to the issue
of ensuring that you can deal with a reference parameter. Indeed in most
implementations these will be *identical* issues.
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 4:14 AM
> I remember the argument, but I would be very wary of claiming who won or
> lost. This is AI-108, which is still open.
I believe you mean 109.
> That is, it never really got
> resolved. Indeed, its pretty much impossible to implement pointer
> conversions if static matching does not imply identical representations
But precisely there is no problem because you cannot have representation
clauses for non-first subtypes (even for subtype-specific aspects). This is
what triggered the discussion at the time: Robert wanted to be able to
specify Size for non-first subtypes, and the ARG said no-no (even though
AI-109 is still opened, it doesn't mention specifying Size for non-first
subtype). I believe that Robert went and implemented a Subtype_Size
attribute in his compiler because he thought that was useful.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 8:23 AM
Wrong viewpoint, our customers needed this and we responded (well I guess
you could make that the definition of what we consider useful, which would
be fair). We needed this so that we can duplicate the effect of the Size
clause in Ada 83 if necessary where it is too painful to modify the code
to assume the Ada 95 default size scheme. We implemented two new
attributes Value_Size and Object_Size which are indeed applicable to
subtypes.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 3:17 PM
<<An alternative is to disallow view conversions in certain
cases. Remember that for untagged types, view conversions
only appear when an actual is a conversion, and the mode
is [in] out. This is not a highly used feature of
the language, I would guess. Disallowing its use
for by-reference types (even if they happen to have the
same representation) might not be a major incompatibility.
Disallowing certain rep clauses on by-reference types might
be a bigger incompatibility.>>
Why not just say that such conversions are not permitted if they
would cause a change in representation. That's clearly the spirit
of conversions of non-scalar objects in such positions anyway, and
I agree with Randy, this would be a negligible impact restriction
(indeed neither Rational nor GNAT allows this construction, for
different reasons, and certainly we have never had the "bug"
reported that we do not allow them, so they cannot be that common :-)
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 3:26 AM
> An alternative is to disallow view conversions in certain
> cases. Remember that for untagged types, view conversions
> only appear when an actual is a conversion, and the mode
> is [in] out. This is not a highly used feature of
> the language, I would guess. Disallowing its use
> for by-reference types (even if they happen to have the
> same representation) might not be a major incompatibility.
> Disallowing certain rep clauses on by-reference types might
> be a bigger incompatibility.
I can live with this rule, as long as the provision "even if they happen to
have the same representation" is kept (because then we don't have to look at
the representation).
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 7:50 AM
Well we already have semantics that depend on whether representation
clauses are present, contrary to Pascal's supposed invariant:
9.10
1 If two different objects, including nonoverlapping parts of the same
object, are independently addressable, they can be manipulated concurrently
by two different tasks without synchronization. Normally, any two
nonoverlapping objects are independently addressable. However, if packing,
record layout, or Component_Size is specified for a given composite object,
then it is implementation defined whether or not two nonoverlapping parts of
that composite object are independently addressable.
So I think the proper condition, quite consistent with the above viewpoint
is that the view conversion should be permitted if no representation
clauses are given for either item, but are forbidden if representation
clauses are given for either item.
It is unnecessarily restrictive to forbid it in the case where there
are no rep clauses, and as Erhard says, no point in providing yet
another reason to avoid the LIMITED keyword.
One could also allow it in the following situations:
1. Derived type which inherits all its representation aspects from the
parent type.
2. Two types for which identical sets of rep clauses are given
For *SURE* we cannot permit it in the following case
3. Rep clause given for one type, which just happens to confirm the
default representation and therefore "is the same as" the representation
for the other type.
There definitely IS an invariant that the front end of an Ada compiler
does not need to know the layout of composite types, and that's something
we definitely cannot break (GNAT for example absolutely depends on that,
because layout is done deep in the backend, long after all legality
checks of this kind are complete)
So if we go the route of allowing certain view conversions to be illegal,
then we need to discuss which.
Note that if we do the following
1. Allow implementations to reject rep clauses on limited types as Pascal
thinks is reasonable.
2. Allow implementations to reject conversions if and only if there is
a change of representation known to the front end (points 1 and 2 above,
but NOT 3), or more conservatively point 1 alone.
Then everyone can live with this. Pascal does not have to make any
changes in the Rational compiler, Robert does not have to make any
changes in the GNAT compiler (though the error message could be
more informative :-)
At this stage in the game, I think you can assume that the major Ada
vendors have put into their compilers the features that their customers
really need, including issues of portability, since we are all faced
with customers moving from one compiler to another who worry about
portability issues (in fact their worry goes far beyond the minimal
RM requirements, you can tell a customer -- sorry this feature from
compiler X is not in the RM, so you are wrong to expect it in GNAT,
but the real market does not work that way, we have all been subject
to pressure to implement all kinds of implementation dependent stuff
in our compilers for portability purposes, e.g. all the DEC Ada
attributes and pragmas in GNAT.
This means that placing new requirements on vendors to pass new ACATS
tests that test new changes or interpretations in the language at this
stage will almost always force vendors to spend time in inappropropriate
ways.
a) I think it would be silly to make Rational waste time implementing
rep clauses that their customers do not need.
b) I think it would be silly to make GNAT waste time (and cause its
customers incompatibilities) by disallowing rep clauses that it
now allows.
Therefore we should look for solutions that require neither, but still
make reasonable semantic sense. When you initially design a language
where there are no implementations, you can always do things completely
cleanly. Once there are implementations you compromise, especially on
non-important things.
I have NEVER argued that I think the rep clauses in question MUST be
accepted by an Ada 95 compiler. I have argued that I think the RM
currently says they should be accepted. This discussion started
if you remember over the question of whether it is necessary to
take the trouble to worry about this at the ARG level. These
discussions clearly show that it is.
Anyway going back to points a and b above, I think it is important here
to do nothing that causes unnecessary disturbance. One way of doing
this is to do absolutely nothing here, and forget we ever noticed
this issue.
That makes me uncomfortable, but I could live with it. My preferred
solution is to try to fix the RM with minimal effort so that
both a) and b) points are taken into full account.
We still do not have input from other compilers, Tuck, what's the
Intermetrics story here?
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 8:39 AM
It is true that this paragraph (9.10(1)) is a Static Semantics rule, but it
doesn't seem to have any bearing on Legality Rules. What I am really concerned
about are legality rules, ie cases where a construct (which is not a
representation item) is legal or not depending on representation choices.
> One could also allow it in the following situations:
>
> 1. Derived type which inherits all its representation aspects from the
> parent type.
>
> 2. Two types for which identical sets of rep clauses are given
These are interesting suggestions, and certainly more acceptable than "when
the representation happens to be the same by sheer luck". Two issues come
to mind, though:
1 - What do you do in generics, where you don't know whether or not the
formal types have representation clauses? I suppose you have to recheck in
the specification and assume the worst in the body.
2 - I wonder if a view conversion can happen before the freezing point of
either type. If that's possible, then we'll need a special rule, as it
could be that the set of representation clauses is not known when the view
conversion occurs.
Of course, whatever fix we do to the view conversion side with will require
violating the privacy of private types. That's sobbering, but then that's
because the notion of by-reference types itself violates the privacy. Sigh.
> 2. Allow implementations to reject conversions if and only if there is
> a change of representation known to the front end (points 1 and 2 above,
> but NOT 3), or more conservatively point 1 alone.
If we wanted to go that way, it would be "require implementations to reject
conversions", not "allow". The last thing we want is
implementation-dependent legality rules.
> One way of doing
> this is to do absolutely nothing here, and forget we ever noticed
> this issue.
>
> That makes me uncomfortable, but I could live with it.
Me too.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 9:03 AM
<<It is true that this paragraph is a Static Semantics rule, but it doesn't
seem to have any bearing on Legality Rules. What I am really concerned
about are legality rules, ie cases where a construct (which is not a
representation item) is legal or not depending on representation choices.>>
Please assume that everyone agrees with this
<<If we wanted to go that way, it would be "require implementations to reject
conversions", not "allow". The last thing we want is
implementation-dependent legality rules.>>
Please assume that everyone agrees with this :-)
****************************************************************
From: Erhard Ploedereder
Sent: Thursday, October 19, 2000 4:51 PM
> 2 - I wonder if a view conversion can happen before the freezing point of
> either type. If that's possible, then we'll need a special rule, as it
> could be that the set of representation clauses is not known when the view
> conversion occurs.
Looks like that is indeed possible because of default expressions. E.g.,
something totally harebrained like:
package P is
type A is array ... -- by reference
AObj: A;
end P;
...
use P;
type B is array ... -- by reference
function F(Y: in out B) return Integer;
type C(Discr: Integer := F(B(AObj))) is record .... -- B not frozen here
pragma Pack(B);
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 3:29 PM
<<We have to be careful here, given that tagged types are all by-reference,
and ordinary conversions are value conversions. There is not any (current)
rule prohibiting value conversions of by-reference types, and we have to be
careful if we introduce one to avoid a serious incompatibility.>>
Value conversions are just fine, that's the *proper* way to achieve
change of representation!
The rule I would propose again is simply this. View conversions are
not permitted if there is a change of representation involved.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 18, 2000 3:50 PM
I think *that* would be a serious incompatibility with Ada 83, because you
would be disallowing any conversion in an IN OUT parameter where there was a
change of representation. Note that such IN OUT parameters can be passed by
copy/result as long as the type in question is not a by-reference type.
(Parameters passed by copy-result still are technically view conversions.)
I think the rule has to be:
View conversions are not permitted for untagged by-reference types if there
is a change of representation involved.
(Because those don't have the option of falling back to copy semantics.)
Then, of course, we have to figure out what "change of representation"
means. :-)
(13.6 never defines that as a term, even though it's the title of the
clause.)
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 4:06 PM
Yes, indeed, that's what I meant, but did not say clearly.
Change of representation simply means that one or more representation
attributes differ for the two types. I don't think that's so hard to
define.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 18, 2000 3:28 PM
<<Considering that view conversions occur everywhere in OOP (because of
conversions to the parent type) I would be extremely concerned that changing
anything in this area would break existing code...>>
View conversions where there is a change of representation certainly don't
appear in a compiler which forbids this from happening, so this is simply
a bogus argument.
Disallowing the rep clauses might certainly break existing code in the
GNAT case, but not in the Rational case.
But disallowing view conversions where there is a change of representation
cannot break either GNAT or Rational code, since neither compiler allows
this.
(for interest what does the intermetrics front end do here?)
I am certainly not strongly arguing that a compiler be forced to accept
these rep clauses (I really don't care if compilers other than GNAT do
or do not accept particular rep clauses, because in practice, we find
that most real apps have to go far beyond the rather pathetic minimal
rep clause requirements of the RM. This means that whatever the ARG
decides in this area, GNAT will accept many rep clauses not required
by the RM, and which therefore may or may not be accepted by other
compilers.
With my purity-of-language hat on, I think that if there are cases of
rep clauses mandated by the RM that are not accepted by some compiler,
then EITHER the compiler OR the RN should be fixed (I really don't
care too much which).
But the issue here is quite different, Pascal is arguing that other
compilers be forced to disallow programs that they currently allow.
That definitely could break existing code.
So my recommendation here is that a compiler not be forced to accept
rep clauses on by-reference types. This avoids someone creating a
test for this, and Rational wasting time implementing what they
see as a useless feature. It is very damaging when ARG rulings have
this effect.
But also, a compiler should be allowed to accept the rep clauses and
reject the conversion (otherwise GNAT has the same complaint, someone
will make a test, and actually the effect is worse, because we don't
know how to implement this in an upwards compatible manner).
So Pascal, how does that sound to you? Does that make sense?
There may be people who feel that the rep clauses must be accepted if
we change things so that the conversion can be rejected as illegal,
but I am not in favor of that approach.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 18, 2000 4:13 PM
> There may be people who feel that the rep clauses must be accepted if
> we change things so that the conversion can be rejected as illegal,
> but I am not in favor of that approach.
Having *my* purity of language hat on, I can't see why we should make two
changes to the language when one will fix the problem.
It clear that if we want to disallow the conversions, that requires an RM
change.
Similarly, disallowing the rep. clauses requires an RM change (if Annex C is
in force, and otherwise nothing is required so there is no problem).
I don't see a reason to make two unrelated RM changes to fix one problem.
The issue of a test is an interesting one; if we change the view conversion
rule, by all means we ought to have test(s). But such a test would be
applicable only to an implementation claiming conformance to Annex C (at
least, we could only require it there). There certainly is nothing to test
for an rep. clause rule changes (I think the ACATS mainly tests for required
Annex C support; you usually can't test that something is not supported,
because it could be in most cases).
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 4:07 AM
> So my recommendation here is that a compiler not be forced to accept
> rep clauses on by-reference types. This avoids someone creating a
> test for this, and Rational wasting time implementing what they
> see as a useless feature. It is very damaging when ARG rulings have
> this effect.
>
> But also, a compiler should be allowed to accept the rep clauses and
> reject the conversion (otherwise GNAT has the same complaint, someone
> will make a test, and actually the effect is worse, because we don't
> know how to implement this in an upwards compatible manner).
>
> So Pascal, how does that sound to you? Does that make sense?
I agree with Randy that having two different changes to the language to plug
one hole is ugly. Moreover, your proposal destroys portability in a big
way. It's one thing to have representation clauses that fail to port from
one compiler to another (users won't be too surprised) but it's another
thing to have view conversions that fail to port from one compiler to
another. I would also want more details on how rejecting the conversion is
supposed to play with generics.
As you can imagine, my preference goes to rejecting the rep clause. My
second choice is Tuck's proposal, i.e. reject view conversions (of nasty
types) regardless of the representation.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 8:16 AM
I think we all agree that we don't want the issue of whether conversions
are legal or not to be implementation dependent. That is another, strong
and convincing reason, not to allow behavior 3. from my previous note:
3. Rep clause given for one type, which just happens to confirm the
default representation and therefore "is the same as" the representation
for the other type.
(here we are talking about conditions that affect the legality of the
conversion).
So that is not arguable (we have to argue about the rules, but no one
I believe is pushing for implementation dependent rules).
It is one thing to have critical runtime semantics be implementation
dependent as in the shared variable case [although I think allowing
impl dependent behavior there instead of saying it was erroneous
was a mistake even in that context], but it is quite another to
allow impl dependent legality conditions [we have examples that depend
on representations already, e.g. when the tag on a case is Integer'Last,
but let's not make more!
Now Pascal says
"I agree that having two different changes to plug one hole is ugly"
Maybe, but if you insist on one change only here, then I think it has
to be the illegality of the conversion (and you leave the rule intact
that requires the rep clauses to be accepted).
Why? Because I think at this stage of the game it is far too contentious
to suddenly invent a change to the language that makes previously legal
and working programs illegal by making a useful construct illegal.
Note that in the case of the "bad" conversions, we can be pretty sure
that althougth theoretically from the RM these are legal, no one can
be using them, since no one knows how on earth they might be implemented.
So insisting on one change only pretty much has to result in being forced
to accept the rep clauses. Of course in my opinon, you ARE accepted to
/// sorry /// required to accept these. I think it is silly to force
anyone to accept these, but perhaps in practice we can just restrain
Randy from making a counter-productive test in this area, and the
status quo can continue of ignoring this requirement, or deciding that
it is not a requirement without discussing it.
Incidentally, we need to be very clear about whether new tests should
appear in any particular area. Test writers tend to get into the
frame of mind that if they can possibly see that failure to write
a test MIGHT allow two compilers to do things differently, then
of COURSE a test must be written. I definitely see Randy operating
in this mode, much as all previous writers of ACVC tests have done.
It is a natural view point, but it is potentially destructive.
For example, it might well be that whatever the outcome of this
discussion is, then the best thing is simply not to write a test.
Of course if we change things the way I recommend (the "two
different changes" solution), then no tests will come to mind :-)
Please note that I am not criticizing Randy here, it's his job to write
tests, or at least part of his job, and so he will do it, unless there
are clear guidelines.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 18, 2000 4:17 PM
Tuck, Pascal, anyone else:
<<View conversions are not permitted for untagged by-reference types if
there is a change of representation involved.>>
Is there a contract model issue with this rule? I wonder how one would
determine this for a generic formal type.
****************************************************************
From: Gary Dismukes
Sent: Wednesday, October 18, 2000 7:07 PM
I was wondering the same thing, but there doesn't seem to be
a way to create a contract model problem using private types
(at least not that I've found so far ;-).
However, in the case of generic formal types, I can think
of one case that seems to be a problem, namely for a generic
formal array type a by-reference component type, where there's
a specification of Component_Size on the actual array type
and another array type inside the generic with a differing
Component_Size (basically the same as Pascal's example).
Again, view conversions won't work. It seems that the worst
case has to be assumed (i.e., that a change of representation
will occur) and the view conversions made illegal. This is
a little nasty since the restriction would have to be applied
even in cases where the type within the generic doesn't have
a specified representation.
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 3:46 AM
I believe you can do many evil things with untagged derived types. Look at
the following example, which is a variation on the alignment example I sent
in a previous message:
type T1 is limited record
I : Integer;
end record;
for T1'Alignment use 4;
type T2 is new T1;
for T2'Alignment use 1;
procedure P (X1 : T1) is ... end;
generic
type F1 is limited private;
type F2 is new F1;
with procedure P (X1 : F1);
package G is ... end;
package body G is
X2 : F2;
begin
P (F1 (X2)); -- Legal?
end;
package I is new G (F1 => T1, F2 => T2, P => P);
If the code for P assumes that the component I is 4-byte aligned, then in
the instantiation we have a problem, because X2 is not necessarily 4-byte
aligned. So it seems to me that in generics you would have to disallow any
conversion that might be a view conversion of by-reference types.
In general, any rule that requires knowledge of the representation will
wreak havoc in generics. Either it will kill the contract model, or it will
have to be checked in an assume-the-worst manner, and that is bound to cause
existing code to become invalid.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 7:55 AM
Here is what GNAT says:
Compiling: k.ads (source file time stamp: 2000-10-18 08:55:04)
8. for T2'Alignment use 1;
|
>>> alignment for "T2" must be at least 4
10 lines: 1 error
I frankly don't see how a compiler can operate if it allows the code that
Pascal quotes on a machine with strict alignment, how on earth would you
avoid assuming the worst when the record was passed by reference (yes of
course this particular record could be passed by value, but we can make
a larger example).
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 8:50 AM
What we do in the non-by-reference case is to generate a properly aligned
copy at the call site. This is part of the "change of representation" that
takes place during the conversion. Of course, we cannot do that for
by-reference types.
As you can imagine, we don't do that just for the fun of it, we have
customers who care.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 9:07 AM
OK, that makes sense and indeed we do the same thing (the message I quoted
to you for that nasty conversion comes precisely from the internal attempt
by the compiler to do this :-)
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 3:17 AM
> That's got to be wrong! The whole model here is that subtype specific
> changes of representation must be cheap for by reference or the whole
> mechanism of calling subprograms with reference parameters breaks if
> there are derived types. Most certainly the understanding is that
> subtype-specific changes of representation are cheap. That should be
> true because
>
> a) for size, in the case of things you would pass by reference, size can
> do nothing more than add or subtract padding space at the end.
>
> b) for alignment, you do not allow specification of alignments that are
> smaller than usual in a way that would cause trouble (at least we don't
:-)
>
> So I think Pascal is right on the description of the change, wrong that it
> is a fallacy.
I am not sure what you are saying, so let me try to clarify what I believe
is wrong with subtype-specific aspects (well, I will focus on Alignment for
now).
Consider the following variation of my original example:
type T is limited record
C : Integer;
end record; -- by-reference
type A1 is array (1..2) of T;
for A1'Alignment use 4;
type A2 is array (1..2) of T;
for A2'Alignment use 1;
procedure P (X : A1) is
begin
... -- Here it seems legitimate for the generated code
-- to assume that the array and its components are
-- 4-byte aligned.
end;
Y : A2 := ...;
...
P (A1 (Y)); -- A view conversion, passed by-reference.
Take for instance the Alpha processor. It is legitimate for a compiler to
generate in the body of P the instructions that assume that data is aligned
(e.g. LDQ). But for the view conversion to work, the compiler would have to
use the instructions that don't assume any particular alignment (e.g.
LDQ_U), or else alignment traps will happen (which would either cause the
program to die, or cause it to slow down by a factor of 1E6).
Are you saying in your item (b) above that you reject the alignment clause
for A2 because the alignment is too small? Fine with me, that's what we do
too. Or are you saying that there is really no problem in this case?
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 7:35 AM
In your example, you are supposing that the compiler will permit less
than the standard alignment for the record. Here is the output when
you compile your example with GNAT:
8. for A2'Alignment use 1;
|
>>> alignment for "A2" must be at least 4
The RM specifically says:
31 An implementation need not support specified Alignments for
combinations of Sizes and Alignments that cannot be easily loaded
and stored by available machine instructions.
This is *exactly* intended to address the situation where you are on a
machine with strict alignment requirements where an alignment value, like
the one above, would cause efficiency problems.
Note also that once again, in your example, the difficulty is caused
specifically by the kind of conversion that we wish to make illegal.
Yes, a compiler can get itself into trouble by supporting inefficient
alignments and trying to allow view conversions when representations
differ, but we all agree that there is a problem with these conversions
in this context anyway.
That does not detract from the general idea that when you pass arguments
by reference there are no expensive implicit conversions from subtype
specific attributes (horrible term incidentally, calculated to confuse,
and successful in that aim -- many of our users assume that subtype
specific attributes should be able to be specified for subtypes -- silly
them :-)
****************************************************************
From: Robert A Duff
Sent: Thursday, October 19, 2000 8:01 AM
When the term was invented, you *were* able to do that. We added the
rule you don't like at the last minute.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 8:55 AM
Yes, I know that well, and it leaves the language in a mess, because you
can no longer influence the size behavior of subtypes, whereas in practice
you could in Ada 83 (because subtypes had the same size behavior as the
base types in most Ada 83 compilers).
****************************************************************
From: Pascal Leroy [pleroy@RATIONAL.COM]
Sent: Thursday, October 19, 2000 7:56 AM
> 8. for A2'Alignment use 1;
> |
> >>> alignment for "A2" must be at least 4
>
> The RM specifically says:
>
> 31 An implementation need not support specified Alignments for
> combinations of Sizes and Alignments that cannot be easily loaded
> and stored by available machine instructions.
Well, I'm perfectly happy with GNAT rejecting the above alignment clause, in
fact we do the same.
On the other hand, in the example that I was mentioning (Alpha) it's a
strech to say that you cannot easily load a 4-byte quantity which is not
4-byte aligned. In fact there is an instruction for that purpose. On other
architectures, granted, this may be impractical. Evidently the decision to
accept or reject the clause has to be highly target-dependent.
Note that in the case of Alpha, there is no reason to reject the above
alignment clause for a non-by-reference type. But then again, I am not
interesting in legislating the level of support of representation clauses.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 8:54 AM
Well easily is deliberately a vague word here, allowing an implementation
dependent decision. I would say that the degradation in code quality by
having to assume worst case alignment for all by-reference parameters
definitely qualifies as violating "easily". The penalty is quite considerable
(try measuing this on late model alpha's and you will see what I mean).
On the other hand, on an architecture like the ia32 where unaligned
accesses are handled automatically at the instruction level, there is
no reason to reject this alignment clause (I think we still do, but
it is hard to justify in that case).
****************************************************************
From: Erhard Ploedereder
Sent: Wednesday, October 18, 2000 8:28 PM
Robert writes:
> I am concerned that prohibiting useful rep clauses for by reference types
> just so that such conversions can work is far too draconian. I would
> prefer a solution that just makes the conversions invalid.
I second that, quite emphatically. Such a restriction would be really
bad news and yet another cause why people would omit "limited" from their
vocabulary, because any record with a limited component could no longer be
rep-spec'ed.
Pascal wrote:
> I entirely disagree with your proposed fix. The component size clause is
> really what's causing trouble, an implementation must be allowed to reject
> it, period.
For the generic example, I agree. And so does the RM : 13.1(23)
or do you see this differently ? On the non-generic example, which is
actually of a quite different nature, I disagree for the reason above
(and some reasons below).
Pascal continues:
> Considering that view conversions occur everywhere in OOP (because of
> conversions to the parent type) I would be extremely concerned that changing
> anything in this area would break existing code...
We're not touching view conversions of tagged types. Luckily, there is no
way to change representation characteristics during tagged type derivation,
or standard implementation models for OOP would come to a screeching halt.
So, no need to be concerned there, since there isn't a problem there to be
solved.
Tuck writes:
> Why not just say that such conversions (view conversions of untagged
> by-reference types) are not permitted if they
> would cause a change in representation. That's clearly the spirit
> of conversions of non-scalar objects in such positions anyway, and
> I agree with Randy, this would be a negligible impact restriction
That fine with me (with the qualification that I put in, which I
believe you meant), but it clearly goes against Pascal's argument that
static semantics mustn't depend on representation aspects.
Robert proposes:
> So my recommendation here is that a compiler not be forced to accept
> rep clauses on by-reference types. This avoids someone creating a test...
A wise compromise. :-) Depends on how strongly we believe in Pascal's
meta-argument vs. introducing an implementation-dependency.
(You can beat me into it, but it takes some beating..:-)
--------
Meta-rumblings of a semanticist....
I am sufficiently worried about the narrowness of the path we're walking by
the position that a "typed view" is merely a logic view, not also a physical
view. Only a very careful crafting of the rules for where view-conversions
can and cannot occur prevents disaster.
For example, I went off to figure out whether I can have a view-conversion
as actual to a generic formal (untagged) IN OUT object. I guess I cannot,
because the actual isn't termed an "actual parameter", but a "generic actual
parameter", so that 4.6(5) doesn't apply. This is such a narrow distinction.
Or am I wrong ? In that case, I have absolutely no way of understanding the
semantics of generic formal objects anymore (and this has nothing to do with
by-reference types), when the actual is a view-conversion.
End of Example.
On the OOP side, the meaning of a view conversion is very clear: an
assertion that I want the object treated as if it were of this view,
with a language guarantee that the object actually has all the
representational and operational properties that the view promises.
(It may have more, but not less.) These semantics compose nicely with
the semantics of all the constructs where the view conversions can
conceivably occur.
I really have a problem mapping this understanding to the meaning (or find
any other meaning) of "view conversion" in the following example:
X: Float;
procedure foo(Y:Integer);
foo(Integer(X));
This is a view conversion by the RM. What does it mean ? "Logically X is now
an Integer" ??? The only reason that this will work at all is because it
will be immediately followed by an implicit conversion to Integer for
passing the parameter. But semantically, this is rubbish, because the
implicit conversion takes something that it "view"s as Integer and makes it
Integer. Converting an Integer to an Integer and assigning it is a bit copy
operation in my book, not some involved change in representation. So the
semantics do not compose at all.
For the original example with the two arrays (assume that they are
non-limited), the language semantics allow passing the array by reference,
applying yet another view conversion to the type of the formal. Now, we know
that this will not (sensibly) work at the implementation level, but why are
we getting into this situation at all ? This interpretation should not be
possible in the first place (and it wouldn't, if a conversion between types
of conflicting representation were always a value-conversion).
P.S. Sorry this got longer than intended.
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 4:00 AM
> Such a restriction would be really bad news and yet another cause why people
> would omit "limited" from their vocabulary, because any record with a
> limited component could no longer be rep-spec'ed.
Have you seen many people using "limited", lately :-)
> > The component size clause is really what's causing trouble, an
> > implementation must be allowed to reject it, period.
>
> For the generic example, I agree. And so does the RM : 13.1(23)
> or do you see this differently ?
Right, 13.1(23) gives permission to reject the clause in a generic.
> Tuck writes:
> > Why not just say that such conversions (view conversions of untagged
> > by-reference types) are not permitted if they
> > would cause a change in representation. That's clearly the spirit
> > of conversions of non-scalar objects in such positions anyway, and
> > I agree with Randy, this would be a negligible impact restriction
>
> That fine with me (with the qualification that I put in, which I
> believe you meant), but it clearly goes against Pascal's argument that
> static semantics mustn't depend on representation aspects.
The only message from Tuck that I saw on this topic was that he wanted to
disallow view conversions of untagged by-reference types
_even_if_the_representation_is_the_same_. Did I miss something? I can live
with Tuck's proposal, I cannot live with yours.
> Depends on how strongly we believe in Pascal's
> meta-argument vs. introducing an implementation-dependency.
> (You can beat me into it, but it takes some beating..:-)
It's not only an implementation-dependency. As I indicated earlier, this
causes trouble in generics. You have two options there: either you say
"assume the worst", and I believe this is going to create terrible
incompatibilities. Or you say "we were not really serious about this
generic contract model thing" but then this language is no longer Ada.
I must add that it can also create implementation difficulties. A compiler
may very well check the legality rules _before_ deciding on the
representation of types. If legality rules depend on the representation,
such a compiler would have a hard time. This is not just speculation: our
compiler used to work like that until fairly recently; it turns out that we
did rearchitecturing in this area to accommodate some customer requests, but
for all I know there might be compilers out there which do it that way. (As
I recall the old Alsys technology worked that way, but it's irrelevant now.)
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 8:17 AM
<<Have you seen many people using "limited", lately :-)>>
Yes, we see people using it fairly frequently, I am surprised that you
would think otherwise, perhaps it is because we have more "go-go" Ada 95
enthusiasts. (I could claim it is because of the wonderful capabilities
we provide including the ability to use rep clauses on such types, but
I don't think this would be valid in real life, although I am sure there
are some examples where this is a factor).
****************************************************************
From: Tucker Taft
Sent: Thursday, October 19, 2000 11:31 AM
Erhard Ploedereder wrote:
> ...
> Tuck writes:
> > Why not just say that such conversions (view conversions of untagged
> > by-reference types) are not permitted if they
> > would cause a change in representation. That's clearly the spirit
> > of conversions of non-scalar objects in such positions anyway, and
> > I agree with Randy, this would be a negligible impact restriction
I didn't write the above. I'm not sure who did.
I suggested to make certain view conversions illegal
regardless of whether representations matched.
> ...
> For example, I went off to figure out whether I can have a view-conversion
> as actual to a generic formal (untagged) IN OUT object. I guess I cannot,
> because the actual isn't termed an "actual parameter", but a "generic actual
> parameter", so that 4.6(5) doesn't apply. This is such a narrow distinction.
> Or am I wrong ? In that case, I have absolutely no way of understanding the
> semantics of generic formal objects anymore (and this has nothing to do with
> by-reference types), when the actual is a view-conversion.
Remember that a generic formal IN OUT object is
equivalent to a rename, but with the added requirement
that the renamed object be updatable. Conversions of
untagged objects appearing in a rename are *value* conversions,
and hence are not updatable. So this implies that
a conversion may not be applied for a generic formal
actual object of mode IN OUT.
> End of Example.
>
> On the OOP side, the meaning of a view conversion is very clear: an
> assertion that I want the object treated as if it were of this view,
> with a language guarantee that the object actually has all the
> representational and operational properties that the view promises.
> (It may have more, but not less.) These semantics compose nicely with
> the semantics of all the constructs where the view conversions can
> conceivably occur.
>
> I really have a problem mapping this understanding to the meaning (or find
> any other meaning) of "view conversion" in the following example:
>
> X: Float;
> procedure foo(Y:Integer);
>
> foo(Integer(X));
>
> This is a view conversion by the RM. What does it mean ?
This is *not* a view conversion. For untagged types,
conversions are only view conversions if they are an
actual parameter and the formal is of mode [in] out.
This formal is of mode "in". Now if you changed
this to mode in out, perhaps your question still applies.
The critical thing about a view conversion is that you
can store a value back into the underlying operand
via the conversion.
> ... "Logically X is now
> an Integer" ??? The only reason that this will work at all is because it
> will be immediately followed by an implicit conversion to Integer for
> passing the parameter. But semantically, this is rubbish, because the
> implicit conversion takes something that it "view"s as Integer and makes it
> Integer. Converting an Integer to an Integer and assigning it is a bit copy
> operation in my book, not some involved change in representation. So the
> semantics do not compose at all.
>
> For the original example with the two arrays (assume that they are
> non-limited), the language semantics allow passing the array by reference,
> applying yet another view conversion to the type of the formal. Now, we know
> that this will not (sensibly) work at the implementation level, but why are
> we getting into this situation at all ? This interpretation should not be
> possible in the first place (and it wouldn't, if a conversion between types
> of conflicting representation were always a value-conversion).
It may have been a mistake to use "view" conversion
for the untagged case at all. Remember the key
point is that you can store back into it. However,
if the parameter must be passed by reference, then
the requirements are much more stringent, namely that
the view conversion have an *address* that you can pass.
Clearly a view conversion that might involve a representation
change does not have an address. Hence, I would say
that any conversion of an untagged by-reference type
where a change of representation is *possible*
is necessarily a value conversion, because we can't guarantee
that the conversion has a meaningful address.
Now as far as I can see, the only problem is with arrays,
because 13.1(10) eliminates the problem for non-arrays.
So the rule would be that any conversion of a by-reference
array type to a different array type (as opposed to
simply a different *sub*type) would be a value conversion.
An unfortunate aspect of this rule is that whether an
array is by-reference is not semantically visible.
We could say if the array *might* be by-reference
(i.e. it has any visibly by-reference subcomponent, or any
private subcomponent), then converting it to a different
type is a value conversion.
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 3:04 PM
> Hence, I would say
> that any conversion of an untagged by-reference type
> where a change of representation is *possible*
> is necessarily a value conversion, because we can't guarantee
> that the conversion has a meaningful address.
> Now as far as I can see, the only problem is with arrays,
> because 13.1(10) eliminates the problem for non-arrays.
13.1(10) eliminates the problems created by _type_related_ representation
items for non-arrays. I have shown an example with 'Alignment which I
believe has the same problem, and applies to non-array types. Or do you
think that my example didn't cause trouble?
> An unfortunate aspect of this rule is that whether an
> array is by-reference is not semantically visible.
I appreciate your effort to save the privacy of private types, but it's
hopeless, because we already have legality rules that depend on whether or
not a type is by-reference (see "allow pass by copy" in C.6(12)).
****************************************************************
From: Tucker Taft
Sent: Thursday, October 19, 2000 12:12 PM
Robert Dewar wrote:
>
> Actually our attempt to find out what a view conversion was proved a bit
> surprising, it seems like a lot of conversions are defined as view
> conversions in a surprising manner, but perhaps we are missing something.
The only conversions for untagged types that are view
conversions are conversions of actual parameters, when
the formal is [IN] OUT. That is a pretty rare case
in my experience. On the other hand, for tagged types,
most conversions are view conversions.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 2:07 PM
I find it surprising that a conversion of an integer to a float can be
regarded as a view conversion. I had the image of a view conversion as
a situation where you look at the same bits through different glasses,
but as often occurs, the actuality does not match the intuition, and
indeed at this stage I have no good intuition as to what a view conversion is.
****************************************************************
From: Randy Brukardt
Sent: Tuesday, October 31, 2000 3:15 PM
I think that the best way to look at a view conversion is that it is an L-Value
(using the C terminology): something that can be assigned into (implicitly by
parameter passing; or, for tagged types, explicitly).
I don't think that is *too* hard to visualize; although the name doesn't
exactly connote that...
****************************************************************
From: Erhard Ploedereder
Sent: Thursday, October 19, 2000 12:03 PM
for the sake of the argument, Pascal, would you find a position acceptable
in which THE EXISTENCE of a rep clause is part of the contract of the type
(much like the existence of an "aliased" keyword for the contract of an
object) so the rule would be one in which the existence, not the nature, of
the rep-clause makes an explicit view-conversion illegal (for untagged
by-reference types) ?
****************************************************************
From: Robert Dewar
Sent: Thursday, October 19, 2000 2:06 PM
Sounds reasonable to me, and is quite compatible with the treatment in
the shared variable case.
****************************************************************
From: Pascal Leroy
Sent: Thursday, October 19, 2000 2:56 PM
I suppose I could live with that (which is essentially Robert's proposal if
I understand correctly). I am not too enthusiastic because:
1 - prior to the freezing point, God only knows what the representation
clauses will be,
2 - this violates private parts (representation clauses could be in private
parts),
3 - in generics you'd have to assume-the-worst anyway.
But at least, that doesn't deface the language.
And by the way, don't we also need to include representation pragmas in this
discussion? Take my original array example, and say that the two arrays
have different conventions. Assume furthermore that these conventions
actually result in different layouts (e.g. row-major vs. column major). We
would want to prevent a view conversion in that case, wouldn't we?
(Damn, I have just undermined my own position: I couldn't get too excited
about component size clauses or alignment clauses on by-reference array
types. But I must admit, before Robert jumps in, that forbidding convention
Fortran on a by-reference array type doesn't seem like the right thing to
do...)
****************************************************************
From: Erhard Ploedereder
Sent: Thursday, October 19, 2000 5:54 PM
Surely. The AI should talk about rep. items, not rep. clauses. Convention
is a rep. item.
****************************************************************
From: Robert Dewar
Sent: Friday, October 20, 2000 10:43 AM
And so is pack :-)
****************************************************************
From: Tucker Taft
Sent: Thursday, October 19, 2000 12:34 PM
Randy Brukardt wrote:
>
> Tuck, Pascal, anyone else:
>
> <<View conversions are not permitted for untagged by-reference types if
> there is a change of representation involved.>>
>
> Is there a contract model issue with this rule? I wonder how one would
> determine this for a generic formal type.
As I proposed elsewhere, I believe this only needs to
apply to conversions to a *different* type of arrays
that *might* be by-reference, which means they have a
subcomponent that is "visibly" by-reference, or is private.
****************************************************************
From: Randy Brukardt
Sent: Thursday, October 19, 2000 2:19 PM
A) This doesn't answer the question.
B) It doesn't make any sense: Some of Pascal's examples use 'Alignment,
which is clearly not covered by 13.1(10).
****************************************************************
From: Randy Brukardt
Sent: Thursday, October 19, 2000 12:45 PM
> For example, it might well be that whatever the outcome of this
> discussion is, then the best thing is simply not to write a test.
> Of course if we change things the way I recommend (the "two
> different changes" solution), then no tests will come to mind :-)
If we adopt a legality rule like the one I proposed in another message, then
it should be tested. Especially the "assume-the-worst" part, which would
have an impact on users.
It seems that the danger of the test is more with collateral issues (the
representation clauses) than with the actual objective [Check that the new
view conversion rule is checked]. That could be worked around by allowing
the test to be NA if the compiler rejects the clauses, without any Annex C
requirement.
Note that with the currently proposed rule, we only need to give a
confirming item to trigger the rule:
Type A is limited record...
Type B is new A;
For B'Alignment use A'Alignment;
So there isn't a lot of reason to reject the clause; so we ought to be able
to create tests without making Rational do anything to their handling of
rep. clauses. (Indeed, a test for the generic body part of the rule could be
constructed without any rep. clauses at all.)
Anyway, if there is a concern about compatibility of making some view
conversions illegal, then I think we cannot adopt the rule at all. If we
adopt a legality rule and specifically say we'll never test it, we're simply
bringing a lot of implementation-dependence into an area where there needs
to be none.
So, I think that if we are unwilling to test the legality rule, we shouldn't
adopt it in the first place; that is, label the AI as "No Action".
****************************************************************
From: Randy Brukardt
Sent: Thursday, October 19, 2000 12:12 PM
OK, let me summarize the hundred or so messages that Pascal and Robert have
pumped out overnight. :-)
We want a rule making the view conversion illegal when the representation
*might* differ, testable only by the front-end.
It seems that rep. clauses on the parent type are irrelevant; the derived
type will have the specified representation unless it tries to change it. So
the problem only comes from specifying the representation on the derived
type (whether or not it is different).
Let me propose a rule. (No I haven't tried to word this carefully.)
A view conversion is illegal for an untagged by-reference type in the
following case. Let A be the type which is the ancestor of both the target
and operand types. Then:
* If there is no such type, then the conversion is illegal.
* If the operand type is not A, then the operand type may not have any
representation items.
* Similarly, if the target type is not A, then the target type may not
have any representation items.
In addition to the usual places where legality rules apply, this also
applies to the private part of generic packages. This is checked in an
assume-the-worst manner in generic bodies.
(The first bullet can only happen for arrays. If the types are different, we
have to forget it, because we can't say anything useful about the
representations of the arrays.)
(The last two sentences are necessary to avoid contract model problems.)
I worry somewhat about the compatibility implications of the
assume-the-worst rule, but I don't think we have an alternative. (Any
generic limited private type could be an untagged by-reference type, so this
would disallow all view conversions of such a type in a generic body.
Luckily, the only non-limited by-reference types are tagged types, so this
rule would not apply to generic private types.)
Comments? The description of the rule got a bit complex; we could just
disallow representation items on either the target type or operand type, but
that seems like it would make some useful programs illegal (ones where there
is no implementation problem).
I'll send a separate message on testing this.
****************************************************************
From: Erhard Ploedereder
Sent: Thursday, October 19, 2000 5:00 PM
You're forbidding the following currently legal case, for which there is no
reason to complain:
type A is array(1..10) of T;
type B is array(1..10) of T;
view-converting back and forth between the two is fine.
I'll post a simpler rule in a few moments so you can shoot at it, too. :-)
****************************************************************
From: Erhard Ploedereder
Sent: Thursday, October 19, 2000 5:42 PM
I've tried for my own sake to summarize what has been proposed as solutions
so far with the most salient arguments. I may have missed some, but it may
help others also to find their way in the jungle.. Here goes...
---------------------------------------
Solution 1:
Rep. items are forbidden for untagged by-reference types or their component
types.
Pro: solves the implementation problem of view conversions, is a simple
rule, and avoids portability issues
Con: is a moderate-to-serious incompatibility for existing code;
prohibits a useful capability for the sake of avoiding problems
with view conversions, which may be absent in the user code.
Solution 2:
Rep. items may be rejected for untagged by-reference types or their
component types.
Pro: highest flexibility to implementers
Con: does not solve the implementation problem of view conversions for
those that do support the rep. items, and thus is really no different
from solution 1, which then has to become the default choice of
implementers, unless combined with one of solutions 3 or 4.
Solution 3:
View conversions between untagged by-reference types that have different
representation are illegal.
Pro: solves the view conversion problems, retaining maximum functionality
Con: makes legality rules dependent on implementation characteristics of
types, which would upset several implementations profoundly. Also,
the legality rule would essentially become implementation-dependent.
Has a generic contract problem for the legality of view conversions
inside generics, if formal generic types are involved. The problem
seems to be limited to the case, where a formal generic array type
is involved.
May have a freezing problem.
Solution 4:
View conversions between untagged by-reference types are illegal, if a
rep. item applies to one but not the other type. (Note that this allows
conversions among derived types, when only the parent has a rep. item.
The precise wording would have to say something like:
"...illegal if a representational aspect was specified by a rep. item
applied to one type, but not inherited by the other type")
Pro: solves the view conversion problems.
Con: still a legality rule dependent on representational type properties
(but not on their nature, which seems much more acceptable)
Has the same generic contract problem as solution 3.
May have a freezing problem.
****************************************************************
From: Tucker Taft
Sent: Thursday, October 19, 2000 5:57 PM
What happened to
5) View conversions are prohibited between two
different array types if their component type *might* be
of a by-reference type (i.e. there is a private
or visibly by-reference subcomponent).
That's the one I like.
****************************************************************
From: Pascal Leroy
Sent: Friday, October 20, 2000 2:43 AM
That's the one I like too, except that I believe the problem also exists for
non-array types.
****************************************************************
From: Erhard Ploedereder
Sent: Thursday, October 19, 2000 6:10 PM
Good point. Consider it added. -) (You noticed my gradually emerging
understanding that records and derived types in general aren't a problem,
thanks to 13.1(10), so I misunderstood this to apply only to the avoidance
of the generic contract problem as opposed to being an elegant general rule.
How do we codify *might* ? )
****************************************************************
From: Tucker Taft
Sent: Thursday, October 19, 2000 10:38 PM
That was codified by my "i.e." clause. In other words,
view conversions are prohibited between two different array types
(that share no common ancestor type) if they have a subcomponent
that is private, or a subcomponent of a visibly by-reference type.
****************************************************************
From: Erhard Ploedereder
Sent: Thursday, October 19, 2000 5:08 PM
Hmmm. what about
generic
Type T is limited private;
Type NT is new T;
package blah is
O: T;
procedure P(X: in out NT); -- this time I remembered the "in out" :-)
....P(NT(O))...
This I can certainly instantiate with a by-reference record type and
a type derived from it with different representation items. Can I not ?
****************************************************************
From: Erhard Ploedereder
Sent: Thursday, October 19, 2000 5:14 PM
No, I cannot. 13.1(10).
****************************************************************
From: Tucker Taft
Sent: Thursday, October 19, 2000 5:53 PM
> This I can certainly instantiate with a by-reference record type and
> a type derived from it with different representation items. Can I not?
There is no such thing, because 13.1(10) disallows such
a combination.
****************************************************************
From: Pascal Leroy
Sent: Friday, October 20, 2000 2:43 AM
Randy and I have been trying to draw your attention to the fact that
13.1(10) only covers type-related representation items, not subtype-specific
ones. Maybe we wrong, but then we would like to be educated, rather than
ignored :-)
****************************************************************
From: Randy Brukardt
Sent: Thursday, October 19, 2000 7:25 PM
> There is no such thing, because 13.1(10) disallows such
> a combination.
No it doesn't. It disallowed TYPE-related items, but it doesn't disallow
SUBTYPE-related items. (How many times do Pascal and I have to say that???)
If T and NT have alignment clauses or size clauses, you certainly can get
exactly this problem.
Thus, Tuck's solution is junk.
(Am I talking into the void here? I've sent notes along this line three
times this afternoon...)
****************************************************************
From: Tucker Taft
Sent: Thursday, October 19, 2000 11:21 PM
Hey, watch your language (only Robert is allowed to say "junk" on
the ARG list ;-).
I think we have heard you and Pascal mention subtype-related
items, but some of us continue to ignore that problem, because
the RM already allows the implementation to be very stingy in
what it accepts. Clearly, the implementation will be asking
for trouble if it allows alignment clauses that are smaller
than the default for by-reference types.
Because of this, I don't see any need to add rules to protect
against subtype-specific representation clauses. It is only
the type-related ones that are a problem.
> (Am I talking into the void here? I've sent notes along this line three
> times this afternoon...)
No, but some of us don't believe there is any problem with
subtype-specific rep clauses, since implementation are not
forced to support much of anything for composite types.
I believe that Robert has indicated this several times
as well, so maybe we all need hearing aids ;o)
****************************************************************
From: Robert Dewar
Sent: Friday, October 20, 2000 10:36 AM
<<Randy and I have been trying to draw your attention to the fact that
13.1(10) only covers type-related representation items, not subtype-specific
ones. Maybe we wrong, but then we would like to be educated, rather than
ignored :-)>>
Indeed, this distinction is definitely deliberate, as I said before,
the assumption is that subtype related attributes (size and alignment)
do not affect the ability to reference something via a pointer. These
peculiar view conversions are what cause the trouble, but they are to
do with component size clauses etc anyway, so I am confused.
Alignment clauses and size clauses on Pascal's example do not raise
issues as far as I am concerned (GNAT handles these cases fine).
****************************************************************
From: Randy Brukardt
Sent: Tuesday, October 31, 2000 6:52 PM
I don't see how that could work for 'Object_Size (which is
subtype-specifiable, at least in GNAT). Wouldn't something like:
type Something is limited null record;
for Something'Object_Size use 64;
type Something_Else is new Something;
for Something_Else'Object_Size use 32;
A : Something_Else;
procedure P (L : in out Something) is
begin
L := ...; -- Copies 64 bits(?)
end P;
P (Something(A)); -- A is 32-bits.
cause problems? If not, why not?
(As the one who got the short stick, and who's going to try to write up a
consistent model for 'Object_Size, preferably one that is compatible with what
GNAT does, I'd like to know about any gotcha's before I trip over them.)
****************************************************************
From: Robert Dewar
Sent: Friday, October 20, 2000 10:36 AM
<<I think we have heard you and Pascal mention subtype-related
items, but some of us continue to ignore that problem, because
the RM already allows the implementation to be very stingy in
what it accepts. Clearly, the implementation will be asking
for trouble if it allows alignment clauses that are smaller
than the default for by-reference types.
Because of this, I don't see any need to add rules to protect
against subtype-specific representation clauses. It is only
the type-related ones that are a problem.>>
Exactly, I 100% agree with Randy here [Editor's note: This was Tucker,
not Randy.]
(say, Erhard, is this better, all this technical discussion ?? :-)
****************************************************************
From: Gary Dismukes
Sent: Thursday, October 19, 2000 1:37 PM
Pascal replied:
> I believe you can do many evil things with untagged derived types. Look at
> the following example, which is a variation on the alignment example I sent
> in a previous message:
I was referring specifically to the case of nongeneric private
types when I said I didn't see contract model problems. I agree
there are problems with generic cases (as in the example I went
on to cite with formal arrays, as well as the example you give
in your message, and there are probably a number of others).
> In general, any rule that requires knowledge of the representation will
> wreak havoc in generics. Either it will kill the contract model, or it will
> have to be checked in an assume-the-worst manner, and that is bound to cause
> existing code to become invalid.
Yes, we're in agreement. The rule restricting view conversions
needs to be applied generally within generic bodies, assuming the
worst about formals, which creates potential incompatibilities.
****************************************************************
From: Robert Dewar
Sent: Friday, October 20, 2000 10:44 AM
<<5) View conversions are prohibited between two
different array types if their component type *might* be
of a by-reference type (i.e. there is a private
or visibly by-reference subcomponent).>>
I think that's fine. In practice these kind of conversions will be quite
rare anyway, and restricted like this, even rarer, and in any case, te
great majority of conversions we restrict in this manner are ones that
won't work anyway in any existing implementation.
Tuck, perhaps I missed it, but did you ever say what the Intermetrics
front end (I guess it is the Averstar Front end this year) does in this
csae?
****************************************************************
From: Tucker Taft
Sent: Friday, October 20, 2000 2:14 PM
On the case I just tried, we happily do copy-in/copy-out,
which seems clearly wrong, since the array components
might be task objects, etc.
So clearly compilers are already doing rather different
things with these "view" conversions. Making the construct illegal will perhaps be doing people a favor.
The fact that we have outlawed certain other cases
of array-to-array view conversions makes me feel better
about simply growing that set a bit to accommodate other
similar cases.
****************************************************************
From: Robert Dewar
Sent: Friday, October 20, 2000 10:37 AM
<<> 5) View conversions are prohibited between two
> different array types if their component type *might* be
> of a by-reference type (i.e. there is a private
> or visibly by-reference subcomponent).>>
Hmmm! If view conversion meant what it intuitively means (conversions
that have to be performed by taking a different view), we could say
this more easily :-)
****************************************************************
From: Randy Brukardt
Sent: Friday, October 20, 2000 3:14 PM
> No, but some of us don't believe there is any problem with
> subtype-specific rep clauses, since implementation are not
> forced to support much of anything for composite types.
> I believe that Robert has indicated this several times
> as well, so maybe we all need hearing aids ;o)
OK, but I thought *his* argument was junk (oops, said it again!), but was
too worn out to bother with arguing it.
The logical conclusion of his argument is that 'Alignment is only useful on
base types, and probably only on elementary base types. (Based on his
description, I would expect that the only 'Alignment that you could give in
GNAT is 4. Kinda defeats the purpose of the attribute, don't you think?)
Anyway, I simply can't get worked up enough about alignment to care. The
Intel processors that I work on simply don't have alignment issues that
matter to anything except performance, so the problem doesn't arise.
****************************************************************
From: Robert Dewar
Sent: Friday, October 20, 2000 4:58 PM
<<The logical conclusion of his argument is that 'Alignment is only useful on
base types, and probably only on elementary base types. (Based on his
description, I would expect that the only 'Alignment that you could give in
GNAT is 4. Kinda defeats the purpose of the attribute, don't you think?)>>
Where did you get that strange idea, of course you can give *larger*
alignments, as required by the RM (since of course larger alignments
cannot affect ease of access).
<<We are telling implementors to beware of possible problems with
subtype-specific attributes and derived types. They ought to disallow any
rep. items that would cause such problems. (Gack!)>>
What's the Gack about here? Of *course* you have to only allow rep items
that don't cause trouble, that's what rep items are about, if they cause
unacceptable trouble, you must reject them.
<<The logical conclusion of his argument is that 'Alignment is only useful on
base types, and probably only on elementary base types. (Based on his
description, I would expect that the only 'Alignment that you could give in
GNAT is 4. Kinda defeats the purpose of the attribute, don't you think?)>>
useful only on base types? what kind of nonsense is that? YOu most certainly
cannmot use alignment clauses on subtypes anyway? I just don't know what
you are talking about here!
<<Anyway, I simply can't get worked up enough about alignment to care. The
Intel processors that I work on simply don't have alignment issues that
matter to anything except performance, so the problem doesn't arise.>>
A fatal weakness in attitude, because of course alignmment is *really*
critical. Ada 83 had a horribly weak attitude to alignment, Ada 95
is better but there are still lots of lurking issues with alignment,
in terms of what to allow and what not to allow.
****************************************************************
From: Randy Brukardt
Sent: Tuesday, October 31, 2000 3:50 PM
> Where did you get that strange idea, of course you can give *larger*
> alignments, as required by the RM (since of course larger alignments
> cannot affect ease of access).
But in actual practice there aren't any larger alignments. On most machines,
the only sensible alignments are 1, 2, and 4; and most composite types will
end up with an alignment of 4 (because you can't give an alignment less than
that of any component).
> What's the Gack about here? Of *course* you have to only allow rep items
> that don't cause trouble, that's what rep items are about, if they cause
> unacceptable trouble, you must reject them.
Great, then I don't need to worry about bit packed arrays. :-)
Seriously, most rep. clauses cause a lot of trouble. How do you define
"unacceptable" trouble? Certainly, I would consider supporting generic
formal array types that might be bit packed "unacceptable" trouble; but the
language doesn't really give me the option to ignore them.
> Useful only on base types? what kind of nonsense is that? You most certainly
> cannot use alignment clauses on subtypes anyway? I just don't know what
> you are talking about here!
"Base" type as opposed to derived types. I'm afraid I lapsed into Janus/Ada
compiler-speak here. (Tucker and Bob appropriated many of the terms that we
were already using internally in Janus/Ada; it being pointless to try to
change the names of dozens of functions and rewrite hundreds of comments to
change the terminology, I've just had to try to keep the two sets straight.
> <<Anyway, I simply can't get worked up enough about alignment to care. The
> Intel processors that I work on simply don't have alignment issues that
> matter to anything except performance, so the problem doesn't arise.>>
>
> A fatal weakness in attitude, because of course alignment is *really*
> critical. Ada 83 had a horribly weak attitude to alignment, Ada 95
> is better but there are still lots of lurking issues with alignment,
> in terms of what to allow and what not to allow.
The main problem that I see with Alignment in Ada 95 is that it really seems
to be aimed at cases where the alignment is required. The definition isn't
very useful for machines where only performance is involved (i.e. the Intel
IA32). There, you really want to be able to specify an alignment to use by
default, but you want to be override it to allow packing, etc. (We assume
that the user cares more about space than performance in that case; I figure
that we ought to let the user make the decision...) Janus/Ada actually has
two alignments, the "recommended" alignment, and the "required" alignment.
The "Required" alignment is the same as the Ada 95 one; the "recommended"
one is similar, but doesn't have the rules requiring the same or larger
alignment on composite types.
For instance, it would be nice if integer types had an alignment of 4,
because that would provide the best performance for stand-alone objects and
array components. But we don't want to force all record types to have that
alignment, because it would make packing impossible (especially important
when the record is used in an array). 13.3(26) prevents giving a smaller
alignment for the Ada 95 alignment.
Anyway, this is off-topic.
****************************************************************
From: Robert Dewar
Sent: Tuesday, October 31, 2000 6:19 PM
<<For instance, it would be nice if integer types had an alignment of 4,
because that would provide the best performance for stand-alone objects and
array components. But we don't want to force all record types to have that
alignment, because it would make packing impossible (especially important
when the record is used in an array). 13.3(26) prevents giving a smaller
alignment for the Ada 95 alignment.>>
Very peculliar .. the expected implementation here is that you respect
the efficiency-required alignments (and the efficiency gain is large,
we are not talking about 386 and 486's here) in the default case, but
if a record is packed, then for sure you allow unaligned stuff if the
cost is not too high.
****************************************************************
From: Randy Brukardt
Sent: Tuesday, October 31, 2000 6:48 PM
Well, that is what I'd prefer, but it is clearly disallowed by 13.3(26). Do you
mean that you ignore this rule (I doubt that), or are you using some sort of
"soft" alignment? (The rule says that it applies to "specified" alignments; I
suppose that if you treat "specified" alignments differently than default ones
you can do what you say. But that is precisely what I was discussing; we're
storing the default ("recommended") and specified ("required") alignments
separately, but I suppose other implementations are possible.)
It is clear that 13.3(26) makes the following illegal:
type Some_Int is range 0 .. 2**20;
for Some_Int'Alignment use 4;
type Some_Record is record
Comp : Some_Int;
end record;
for Some_Record use record
Comp at 0 range 0 .. 23;
end Some_Record;
for Some_Record'Size use 24;
for Some_Record'Alignment use 1; -- Nope, illegal by 13.3(26).
-- Use Some_Record in an array.
Despite the fact that there is no implementation problem with this. The space
waste can be considerable in a case like this.
I'd like a way to specify a non-binding alignment, which is not subject to
13.3(26). I doubt it is worth making a formal proposal, however (there aren't
many machines that it would matter on).
****************************************************************
From: Robert Dewar
Sent: Friday, October 20, 2000 10:50 AM
<<If we adopt a legality rule like the one I proposed in another message, then
it should be tested. Especially the "assume-the-worst" part, which would
have an impact on users.>>
Lots of things potentially impact users. The above is what I mean when I
talk about those who write tests getting into the mode of wanting to
write a test whenever they can :-) :-)
The mere fact that something has a potential impact on users does NOT
mean that something should be tested. We always need to discuss how
great the potential impact is.
At this stage in the game, things that have only been discovered recently
are suspect from this point of view anyway (i.e. it is unlikely that they
have wide significant impact). Also we have to look at what kind of
impact is involved. For example, if one compiler accepts a rep clause
and another does not, big deal, I would not test for this, since you
have lots of legitimate cases like this regardless of the tests. This
is a case most often better handled by the market place.
****************************************************************
From: Randy Brukardt
Sent: Friday, October 20, 2000 3:14 PM
Let's summarize the state of the AI that I haven't written yet.
(But it has hundreds of comments!).
The consensus rule to use is:
View conversions are illegal for a conversion between two arrays that do not
have a common ancestor if their component type is has a private or visibly
by-reference subcomponent.
Reasons:
The rule is necessary because two different array types could have different
component sizes, yet a by-reference type cannot be passed by copy.
The "private or visibly by-reference subcomponent" rule essentially means
"might be by-reference". We need to use "might" because one of these
conversions can happen before the type is frozen; we can't tell before the
type is frozen if it is by-reference, but we need to be able to determine
the legality of the conversion.
This rule has the advantage of not breaking privateness (it uses
assume-the-worst for private types of all kinds) and does not require any
knowledge about representation items.
13.1(10) prevents these sorts of problems for type-related aspects of
by-reference derived types. So we don't need a rule to handle them. AARM
13.1(10.b) explains that this rule exists precisely to prevent this sort of
problem.
We are telling implementors to beware of possible problems with
subtype-specific attributes and derived types. They ought to disallow any
rep. items that would cause such problems. (Gack!)
Potential problems:
The rule as written includes all tagged types. Is that intentional, or an
oversight? (Earlier, we only considered untagged types for these rules.)
Do this rule need an assume-the-worst statement for generics? (I don't think
so.)
What about generic derived types? Could the actual be by-reference when the
formal type does not indicate it? (Humm, maybe not, I can't think of a
case.)
Since this rule applies to generic formal private types (at least, it
better, or we have contract model issues), it could make existing programs
illegal that do not actually have a problem. This seems unlikely. In a
generic body, it seems very unlikely (arrays of generic formal types seem
unlikely, two such types in the same body seem even more unlikely, and
conversions between them seem even more unlikely); but it might happen for a
private type whose full type is not by-reference. Since users could run into
the rule, it ought to be tested (and remember again that rep. items are not
needed to trigger the rule).
Note that Erhard's example of a view conversion before freezing is bogus,
because it uses a function with an IN OUT parameter. I'd like to see those
for other (OOP) reasons, but unless we're seriously considering that as an
amendment, I don't do think we have an example of a freezing problem.
Indeed, I don't think you can use an untagged view conversion in a default
expression, because they only occur in IN OUT parameters; which cannot
appear in a function, and procedures can't appear in an expression. Does
anyone have a *legal* example of a freezing problem?
****************************************************************
From: Tucker Taft
Sent: Friday, October 20, 2000 5:47 PM
> The rule as written includes all tagged types. Is that intentional, or an
> oversight? (Earlier, we only considered untagged types for these rules.)
Arrays are never tagged, so you mean it includes all
array-of-tagged, I presume. Yes I suppose it does,
but array-of-tagged are even rarer than other kinds
of array-of-by-ref I would guess.
> Do this rule need an assume-the-worst statement for generics? (I don't think
> so.)
Private seems to cover it.
> What about generic derived types? Could the actual be by-reference when the
> formal type does not indicate it? (Humm, maybe not, I can't think of a
> case.)
No, all types in the same derivation class are by-reference,
or not by-reference.
****************************************************************
From: Jean-Pierre Rosen
Sent: Saturday, October 21, 2000 4:38 AM
> Note that Erhard's example of a view conversion before freezing is bogus,
> because it uses a function with an IN OUT parameter. I'd like to see those
> for other (OOP) reasons, but unless we're seriously considering that as an
> amendment, I don't do think we have an example of a freezing problem.
> Indeed, I don't think you can use an untagged view conversion in a default
> expression, because they only occur in IN OUT parameters; which cannot
> appear in a function, and procedures can't appear in an expression. Does
> anyone have a *legal* example of a freezing problem?
>
At long last, we have a *technical* reason for not allowing in out parameters
in functions! (sorry, couldn't resist :-)
****************************************************************
Questions? Ask the ACAA Technical Agent