Version 1.3 of acs/ac-00154.txt

Unformatted version of acs/ac-00154.txt version 1.3
Other versions for file acs/ac-00154.txt

!standard 8.5.1(6)          07-12-06 AC95-00154/01
!standard 8.5.4(7)
!class confirmation 07-12-06
!status received no action 07-12-06
!status received 07-11-27
!subject Historical question: why are constraints ignored in renamings?
!summary
!appendix

From: John Barnes
Sent: Tuesday, November 27, 2007  5:44 AM

One of my colleaugues in the BSI has raised a question about renaming. He
needs to refute someone who says that Ada is stupid.

I apologise if this is not proper Ada 2005 business.

But first let me recap the issue of default subprogram parameters because
that might be relevant.

In preliminary Ada, any default expression was evaluated when the subprogram
spec was elaborated. It was like that in the 1979 SigPlan notices and in the
July 1980 proposed standard

The first edition of my book (early 1982) says that as well.

There was a problem with matching spec and body if I recall correctly since
the value might be different when the body was elaborated. As a consequence
it was made dynamic and only evaluated when required. That was nice because
the default spirit in one of my examples could then be Gin in the week and
Vodka at weekends. This probably happened some time in 1982.

Thus by July 1982 (draft revised mil std 1815) the manual had changed to say
that the default expresion was evaluated when used. As it is now of course.

Now with regard to renaming. The issue is why are constraints given by the
renaming ignored and when did that happen? The 1979 preliminary Ada is
pretty vague but hints that the constraints are unchanged - it doesn't say
that new ones are ignored so perhaps it implies they have to match. The July
1980 proposd standard is much clearer and says that constraints must be the
same (and raises C_E if they are not). The July 1982 manual says that
constraints are unchanged by the renaming.

Similarly, the first edition of my book (early 1982) says "at the time of
elaboration of the renaming declaration any constraints must match". Whereas
the second edition is as now and says new ones are ignored.

The various rationales are unhelpful. And I can find no minutes of meetings
from that time.

Questions

Were the two issues related?  And why did we end up ignoring new
constraints? (I usually mutter something about well you can just do a quick
jump (into the ocean perhaps).)

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

From: Tucker Taft
Sent: Tuesday, November 27, 2007  7:29 AM

I had presumed that new constraints were ignored
because of the equivalence with generic formal
subprograms and formal IN OUT objects.  It would
be limiting to require the constraints to match
for such generic formals, and since they are
defined in terms of renaming, it would break
the equivalence if renaming required exact matching.

Here is another reason: before Ada 95, X'Base could
only be used as the prefix of an attribute reference.
In particular, it couldn't be used for the subtype
of a formal parameter.  However, the formal parameter
subtype for the predefined operators are generally
the base subtype, and if there is no way to state
that, then renaming of predefined operators would
not be possible.

Of course times have changed, and we might consider
tightening this up in the future.  I suppose one
step to that would be defining some kind of "restriction"
in the High-Integrity annex requiring that constraints
in renames must match.

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

From: John Goodenough
Sent: Tuesday, November 27, 2007  10:43 AM

Remarkably enough, I can answer this question. (Apparently it does pay
to keep documents in your office for 25 years!)

------

On June 1, 1982, Kit Lester of the Language Design Team wrote a comment
directly addressing why constraints are ignored in renaming:

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

This comment paraphrases a discussion at the November 1981 DR's meeting,
for those without access to the minutes (LSN.250, pages 6 and 7).  See
also comment #753 by George Romanski of Ada-Europe.

Many users will be shocked that explicit constraints on type marks
appearing in renaming declarations of objects or subprograms (or in
generic formal declarations defined in terms of renaming) will be
ignored.  Eg:

        subtype POSITIVE is INTEGER range 1 .. NATURAL'LAST
        POS : POSITIVE;
        subtype SMALL is INTEGER range -9 .. +9;
        SML : SMALL renames POS;  -- legal
          ...
        SML := 10;   -- not small, but ok; shock
        SML := -1;   -- small but raises CONSTRAINT_ERROR; shock

Various restrictions on the type mark have been considered, but
rejected:

(1)     The type mark must be unconstrained.  Rejected because the type
        might be invisible where the subtype is visible, and because
        it would preclude writing subtype marks implying the same
        constraint.

(2)     Requring the type mark be followed by 'BASE; this is saying what
        is meant, but

          - gives an attribute returning a type (whereas at present
            'BASE must be followed by another attribute, i.e., it
            modifies the following attribute rather than existing in
            its own right);

        and

          - requires radical syntax changes for renaming of subprograms
            with parameters or results, or an obscure restriction to
            achieve the same effect.

(3)     Demanding "equivalent constraints" requires new equivalence
        rules, including means for defining "sufficiently equal"
        floating point values resulting from different expressions.

The alternative of not ignoring explicit constraints is also
unacceptable; if the assignment SML := -1; in the above example did NOT
raise CONSTRAINT_ERROR then the variable POS would have a negative value
...

In summary: in the absence of an acceptable solution, the problem must
be accepted.

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

From: Tucker Taft
Sent: Tuesday, November 27, 2007  11:47 AM

Interesting.  It seems like all of the problems identified
now have reasonable solutions in Ada 95, so we could probably
shift toward requiring static matching of constraints.
As I suggested in my earlier note, providing a "Restriction"
in the High-Integrity Annex might be a good first step.

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

From: Robert A. Duff
Sent: Tuesday, November 27, 2007  1:32 PM

> Remarkably enough, I can answer this question. (Apparently it does pay
> to keep documents in your office for 25 years!)

Good to hear from you, John.  Thanks for keeping those docs for 25 years!

If you have machine-readable copies of these historical documents, I think it
would be a good service to the community if you could get Randy to put them up
on the web site.

> (1)     The type mark must be unconstrained.  Rejected because the type
>         might be invisible where the subtype is visible, ...

That part seems confused, to me.  The same confusion that caused the language
designers to make with_clauses intransitive.  And not to allow with_clauses on
private parts.

>...and because
>         it would preclude writing subtype marks implying the same
>         constraint.

Indeed.

>           - gives an attribute returning a type (whereas at present
>             'BASE must be followed by another attribute, i.e., it
>             modifies the following attribute rather than existing in
>             its own right);

Interesting that this rule was removed in Ada 95 (but we added a restriction on
'Base of composites).

>           - requires radical syntax changes for renaming of subprograms
>             with parameters or results, or an obscure restriction to
>             achieve the same effect.

I've no idea what that means -- I don't see any syntactic issues.

> (3)     Demanding "equivalent constraints" requires new equivalence
>         rules, including means for defining "sufficiently equal"
>         floating point values resulting from different expressions.

Interesting again -- we now have the concept of "static matching" on subtypes.
And it nicely sidesteps the floating point issue.  ;-)  Now that we have this
concept, the obvious rule is to require static matching, except that would be
incompatible.  Although as Tuck pointed out, it could be a Restriction.
It could also be a compiler warning.

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

From: Robert A. Duff
Sent: Tuesday, November 27, 2007  1:42 PM

> One of my colleaugues in the BSI has raised a question about renaming. He
> needs to refute someone who says that Ada is stupid.

Maybe "stupid" is overstating the case, but this ignoring of subtypes on
renamings is clearly a language design flaw, no matter what the original
reasoning was.  A relatively minor flaw.

Perhaps your colleague should admit that Ada is imperfect.  ;-)

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

From: John Goodenough
Sent: Tuesday, November 27, 2007  1:57 PM

> If you have machine-readable copies of these historical documents, I think it
> would be a good service to the community if you could get Randy to put them
> up on the web site.

My files are, unfortunately, just in hard copy at this point.

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

From: Jeff Cousins
Sent: Friday, May 23, 2008  5:47 AM

One of the guiding rules of Ada is often said to be "no surprises".

It therefore comes as some surprise that any constraints given by a
renaming are ignored.

For example:

procedure  Long_Name (X: Positive);

-- Conformance of constraints not enforced
procedure Short_Name (Y : Integer) renames Long_Name;

Short_Name (-1); -- Compiles but raises Constraint_Error when run


I am informed various restrictions on the type mark were considered, but rejected:
"
(1)     The type mark must be unconstrained.  Rejected because the type
        might be invisible where the subtype is visible, and because
        it would preclude writing subtype marks implying the same
        constraint.

(2)     Requring the type mark be followed by 'BASE; this is saying what
        is meant, but

          - gives an attribute returning a type (whereas at present
            'BASE must be followed by another attribute, i.e., it
            modifies the following attribute rather than existing in
            its own right);

        and

          - requires radical syntax changes for renaming of subprograms
            with parameters or results, or an obscure restriction to
            achieve the same effect.

(3)     Demanding "equivalent constraints" requires new equivalence
        rules, including means for defining "sufficiently equal"
        floating point values resulting from different expressions.

The alternative of not ignoring explicit constraints is also unacceptable;
if the assignment SML := -1; in the above example did NOT raise CONSTRAINT_ERROR
then the variable POS would have a negative value ...

In summary: in the absence of an acceptable solution, the problem must be accepted.
"

Please could this matter be re-visited?
Re (2), Ada 2005 has opened up some new possibilities, i.e. 'Base is now allowed
on its own.
Re (3), Constraints are most often applied to integer types, generally proving
problematic in practice for floating types, so a solution that only applied to
discrete types would still be a big step forward.

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

From: Randy Brukardt
Sent: Friday, May 23, 2008  3:03 PM

Based on the fairly recent ARG discussion (from which the ancient e-mail you
quoted comes), there is no real technical problem here: Ada 95 added static
matching rules (which Ada 83 did not want to do), and simply requiring static
matching would work fine without the current anomolies. (And there would be no
reason to have different rules for different kinds of types).

However, this problem is mostly political. A change to require static matching
on renames (and various generic formal parameters, for which the rules are
intentionally the same as renaming) would be incompatible with all previous
versions of Ada. How incompatible depends on how often this capability actually
occurs in practice - my personal guess is that it is fairly common. I think
most people rename operators without using 'Base, and that would become illegal
if we adopt static matching. One could try to adopt some "holes" in the rule
to avoid the most common incompatibilities, but that could get very complicated.

Note that the null exclusion rules for renaming were adopted specifically to
avoid surprises (rather than following the "tradition" of ignoring constraints),
and they are very complicated (and for a simple on-off exclusion).

In any case, the only incompatibilites that we will accept as language maintenance
are those to fix outright bugs. It is not possible to argue that something that
is explicitly in the Standard, and has been for 25 years, and has been confirmed
several times, is a bug. Thus any such change would have to wait for the next
major revision of Ada -- and there are no plans at this time for such a revision.
So it will be many years before such an incompatible change could be considered,
and several more before it would appear in compilers.

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

From: Dan Eilers
Sent: Friday, May 23, 2008  3:31 PM

> Thus any such change would have to wait for the next major revision of
> Ada -- and there are no plans at this time for such a revision.

This may be true.  However, WG9's announcement and draft agenda for the
upcoming meeting says there is a "current project to amend ISO/IEC 8652".

See http://www.open-std.org/JTC1/SC22/WG9/n487.txt

# Report of Ada Rapporteur Group: Edmond Schonberg, Chair #  - including
items related to the current project to amend ISO/IEC 8652

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

From: Robert A. Duff
Sent: Friday, May 23, 2008  5:24 PM

> One of the guiding rules of Ada is often said to be "no surprises".
>
> It therefore comes as some surprise that any constraints given by a
> renaming are ignored.

You are right.  This is a flaw in Ada.  Unfortunately, I think you're decades
too late.  We can't fix this, because it would be severely incompatible.

For ex:

    package P is
        type T is range ...;
        ...
    end P;

    with P;
    procedure Q is
        function "+" (X, Y : P.T) return P.T renames P."+";

would be illegal (P.T should be P.T'Base).

I think you are a customer of AdaCore.  You could request that AdaCore implement
a warning in the "surprising" cases.

The Ada RM doesn't really have the concept of "warning".

On the other hand, AARM-2.8 says:

                           Implementation Requirements

  13    The implementation shall give a warning message for an unrecognized
  pragma name.

      13.a  Ramification: An implementation is also allowed to have modes in
            which a warning message is suppressed, or in which the presence of
            an unrecognized pragma is a compile-time error.

On the third hand, "warning" and "error" are not defined in any formal or
even semi-formal way, so the above is a rather questionable rule.

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

From: Jeff Cousins
Sent: Wednesday, May 28, 2008  9:27 AM

Thanks for your reply Randy.

I appreciate the problem of backward compatibility.  Could not there be a
configuration pragma saying to check conformance, so that the default behaviour
would be as before, but such that checking could be switched on?

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

From: Jeff Cousins
Sent: Wednesday, May 28, 2008  9:28 AM

Thanks Bob for your suggestion.  GNAT does already give a warning in such problem cases.

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

From: Tucker Taft
Sent: Wednesday, May 28, 2008  9:48 AM

A "restrictions" pragma might be feasible.  It sounds like your concerns are
more about object renaming than about subprogram renaming, and a restriction
requiring static matching of object subtypes in renaming would seem to be
reasonable.  Whether this needs to be de-jure standardized, or simply a
de-facto standard I can't say.

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

From: Adam Beneschan
Sent: Monday, June 8, 2009  1:22 PM

!topic Possible ambiguity in subprogram renaming declarationsw
!reference 8.5.4(7)
!from Adam Beneschan 09-06-08
!discussion

The following is extracted from ACATS test B85013C:

PROCEDURE B85013C (N : INTEGER) IS

     I : INTEGER;
     O : STRING(1 .. 1);

     SUBTYPE S  IS STRING;                        -- UNCONSTRAINED.
     SUBTYPE S1 IS STRING(1 .. 2);                -- STATIC.
     SUBTYPE S2 IS STRING(1 .. N);                -- NON-STATIC.

     PROCEDURE P3 (X : S2 := (OTHERS => '*'));    -- OK - S2 CONSTRAINED

     PROCEDURE P4 (X : S1 := ('1', OTHERS => '*'))-- OK.
                    RENAMES P3;

The declaration of P4 was illegal before Ada 95, but it became legal with Ada 95
rule changes.  However, I am not 100% clear on what should happen when P4 is
called (if N is something other than 2).  Since this is a B test and there are
still other errors in the test, there is no check to make sure the correct
semantics take place at run time.

8.5.4(7) says that the profile of the new view "takes its subtypes, parameter
modes, and calling convention from the original profile of the callable entity,
while taking the formal parameter names and default_expressions from the profile
given in the subprogram_renaming_declaration."  What is the "default_expression"
in this case?  Specifically, what is the subtype of the default expression, S1
or S2?  Which subtype is used to determine the "applicable index constraint" for
the default expression, as defined by 4.3.3(11)?

My reading is that the constraint of S1 in the renaming declaration doesn't have
any effect on the semantics of anything, and thus the aggregate ('1',
others=>'*') as if S2's constraint is the applicable one.  Thus, if N=5, the
default parameter when P4 is called is actually "1****".  However, GNAT gives a
Constraint_Error when P4 is called with no explicit parameter, indicating that
it thinks the default parameter is "1*", which then raises the exception when
"1*" is converted to subtype S2.  Not that GNAT is always right about
everything.  But when it gives a result contrary to what I think the RM is
saying, in a case where the RM isn't completely clear, I think a clarification
may be necessary.

In fact, if my reading of the RM is correct, this could be very confusing to a
reader.  (Who, looking at the declaration of P4, would think that the default
parameter is actually "1****" or something else depending on N?)  So whatever
the wisdom of allowing parameter/result subtypes in a subprogram renaming
declaration to be different from that of the renamed subprogram (and ignoring
the constraints in the renaming declaration), I suspect that perhaps we should
disallow this in the case of an array constraint.  Perhaps allowing the
parameter subtype in the renaming declaration to be an unconstrained array
subtype is OK.  But I think we should consider adding a restriction that if a
subtype in the profile of a subprogram renaming declaration is a constrained
array, the constraint must statically match that of the corresponding subtype in
the renamed callable entity---or something similar.

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

From: Bob Duff
Sent: Monday, June 8, 2009  2:27 PM

> My reading is that the constraint of S1 in the renaming declaration
> doesn't have any effect on the semantics of anything, and thus the
> aggregate ('1', others=>'*') as if S2's constraint is the applicable
> one.  Thus, if N=5, the default parameter when P4 is called is
> actually "1****".

I agree.

>....However, GNAT gives a Constraint_Error when P4 is  called with no
>explicit parameter, indicating that it thinks the  default parameter is
>"1*", which then raises the exception when "1*"
> is converted to subtype S2.

Sounds like a bug in GNAT.

>...Not that GNAT is always right about
> everything.  But when it gives a result contrary to what I think the
>RM is saying, in a case where the RM isn't completely clear, I think a
>clarification may be necessary.
>
> In fact, if my reading of the RM is correct, this could be very
> confusing to a reader.

Indeed.  This is IMHO a language design flaw.  It apparently confused somebody
writing that part of GNAT, sometime in the distant past.

>..(Who, looking at the declaration of P4, would  think that the default
>parameter is actually "1****" or something else  depending on N?)  So
>whatever the wisdom of allowing parameter/result  subtypes in a
>subprogram renaming declaration to be different from  that of the
>renamed subprogram (and ignoring the constraints in the  renaming
>declaration), I suspect that perhaps we should disallow this  in the
>case of an array constraint.  Perhaps allowing the parameter  subtype
>in the renaming declaration to be an unconstrained array  subtype is
>OK.  But I think we should consider adding a restriction  that if a
>subtype in the profile of a subprogram renaming declaration  is a
>constrained array, the constraint must statically match that of  the
>corresponding subtype in the renamed callable entity---or  something
>similar.

Well, perhaps GNAT should give a warning.

But I don't think it's sufficiently broken to fix the language.
And I think this particular case is no worse than other cases.
I mean:

    P4 (('1', OTHERS => '*'));

who would expect that subtype S1 is ignored and S2 is used instead?
I don't much like the idea of fixing just part of the problem.

I also don't understand why you want to allow String in the renaming. That's
equally confusing -- it makes me think I can pass a string of any length, but I
can't.

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

From: Adam Beneschan
Sent: Monday, June 8, 2009  2:45 PM

> But I don't think it's sufficiently broken to fix the language.
> And I think this particular case is no worse than other cases.
> I mean:
>
>     P4 (('1', OTHERS => '*'));
>
> who would expect that subtype S1 is ignored and S2 is used instead?
> I don't much like the idea of fixing just part of the problem.

The way I phrased my proposed solution didn't have anything to do with default
parameters.  It would make the renaming declaration of P4 (with parameter
subtype S1) illegal regardless of whether the renaming or renamed subprogram had
default parameters.

> I also don't understand why you want to allow String in the renaming.
> That's equally confusing -- it makes me think I can pass a string of
> any length, but I can't.

I was just trying to discern why it was permitted at all to specify different
subtypes in the renaming declaration.  If it were me, I probably would have
required subtype conformance rather than mere mode conformance.  My statement
about allowing an unconstrained array (String) in the renaming was based on my
assumption that there was a good reason for allowing the subtypes to be
different, and guessing that whatever this reason was (which I don't know), it
might dictate that we should allow an unconstrained array as the parameter
subtype when that of the renamed subprogram is constrained.  It's just a guess.
I didn't mean to imply that I *want* the programmer to be able to change the
subtype to unconstrained.  I don't, really.

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

From: Jean-Pierre Rosen
Sent: Monday, June 8, 2009  3:09 PM

> I was just trying to discern why it was permitted at all to specify
> different subtypes in the renaming declaration.  If it were me, I
> probably would have required subtype conformance

There was no notion of subtype conformance in Ada 83, and I think the rule was
set this way because *something* had to be said about it, and presumably Jean
thought that anyway, nobody would do it...

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

From: Bob Duff
Sent: Monday, June 8, 2009  3:15 PM

> The way I phrased my proposed solution didn't have anything to do with
> default parameters.

OK, I misread it.  I just reread it, and you propose to restrict the array case.
I don't see why -- all cases (records, integer, &c) seem equally confusing to
me.  And fixing the problem would be incompatible.  (Only doing arrays is less
incompatible, but still incompatible.)

We don't normally add rules that break existing programs, just because those
programs are confusing.

> I was just trying to discern why it was permitted at all to specify
> different subtypes in the renaming declaration.

It was discussed during the Ada 83 design, and it was recognized as a problem
(to ignore subtypes), but there was some reason people thought it had to be that
way.  I don't remember why.  Maybe this: when you say "type T is range 1..10;"
you get a "+" function whose parameters are sort-of of the base subtype.  But
'Base was restricted in Ada 83 -- you can't say:

    function Blah (X: T'Base; ...) ... renames "+";

In Ada 95, 'Base is still restricted (with different restrictions).
A similar issue would arise for "&".

There might be some generic-related reason(s).  Generic parameter associations
are supposed to be just like renaming.

>...If it were me, I
> probably would have required subtype conformance rather than mere mode
>conformance.

Me, too.

>...My statement about allowing an unconstrained array
> (String) in the renaming was based on my assumption that there was a
>good reason for allowing the subtypes to be different, ...

There was a reason.  I don't think it was a "good" reason.  ;-) At least, that's
what I remember thinking when I read the Ada 83 discussions.  Long time ago.

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

From: Randy Brukardt
Sent: Monday, June 8, 2009  3:39 PM

John Goodenough was nice enough to unearth the answer to this question a few
years ago. (This thread was filed in AC-0154.) He found the following message:


On June 1, 1982, Kit Lester of the Language Design Team wrote a comment directly
addressing why constraints are ignored in renaming:

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

This comment paraphrases a discussion at the November 1981 DR's meeting, for
those without access to the minutes (LSN.250, pages 6 and 7).  See also comment
#753 by George Romanski of Ada-Europe.

Many users will be shocked that explicit constraints on type marks appearing in
renaming declarations of objects or subprograms (or in generic formal
declarations defined in terms of renaming) will be ignored.  Eg:

        subtype POSITIVE is INTEGER range 1 .. NATURAL'LAST
        POS : POSITIVE;
        subtype SMALL is INTEGER range -9 .. +9;
        SML : SMALL renames POS;  -- legal
          ...
        SML := 10;   -- not small, but ok; shock
        SML := -1;   -- small but raises CONSTRAINT_ERROR; shock

Various restrictions on the type mark have been considered, but
rejected:

(1)     The type mark must be unconstrained.  Rejected because the type
        might be invisible where the subtype is visible, and because
        it would preclude writing subtype marks implying the same
        constraint.

(2)     Requring the type mark be followed by 'BASE; this is saying what
        is meant, but

          - gives an attribute returning a type (whereas at present
            'BASE must be followed by another attribute, i.e., it
            modifies the following attribute rather than existing in
            its own right);

        and

          - requires radical syntax changes for renaming of subprograms
            with parameters or results, or an obscure restriction to
            achieve the same effect.

(3)     Demanding "equivalent constraints" requires new equivalence
        rules, including means for defining "sufficiently equal"
        floating point values resulting from different expressions.

The alternative of not ignoring explicit constraints is also unacceptable; if
the assignment SML := -1; in the above example did NOT raise CONSTRAINT_ERROR
then the variable POS would have a negative value ...

In summary: in the absence of an acceptable solution, the problem must be
accepted.

-----------------

The net answer is that the Ada 83 team wasn't able (or willing?) to come up with
a definition of statically matching constraints (alternative fix (3), in Ada 95
terms), which of course Tucker did add to Ada 95.

The problem now is that requiring static matching of constraints (equivalently,
subtype conformance) would be wildly incompatible for existing renames. For
instance, the typical way to write operator renames would be illegal for
predefined operators:

     function "*" (Left, Right : My_Integer) renames My_Package."*"; -- Illegal:
                                              -- Does not statically match

     function "*" (Left, Right : My_Integer'Base) renames My_Package."*"; -- OK.

We probably could probably make some complex set of rules that allows common and
fairly harmless mismatches like the above and eliminate the nastier ones (such
as the both constrained case that Adam notes here). But that seems like a lot of
work for something that is mostly going to cause problems for people. If you
want to try it, please feel free to go ahead and propose something. I'd love to
see the stupidity reduced here.

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


Questions? Ask the ACAA Technical Agent