Version 1.6 of ais/ai-00152.txt

Unformatted version of ais/ai-00152.txt version 1.6
Other versions for file ais/ai-00152.txt

!standard 04.05.05 (17)          00-01-25 AI95-00152/06
!class confirmation 96-09-04
!status Response 2000 00-01-25
!status WG9 approved 98-06-12
!status ARG Approved 11-0-0 98-04-01
!status ARG Approved (with changes) 12-0-1 97-11-16
!status work item 96-09-08
!status received 96-09-04
!priority Medium
!difficulty Medium
!qualifier Clarification
!subject Operators not inherited from root numeric types
!summary
Predefined operators, including those of the root numeric types, are not inherited. Instead, types have predefined operators by specific language rules.
!question
Consider the operators described in 4.5.5(17), such as
function "*" (Left: root_real; Right: root_integer) return root_real;
It would seem logical to assume that root_real is declared immediately within the visible part of package Standard, which means that this operator is a primitive subprogram of type root_real.
By 3.5.6(3), Float is derived from root_real. Does Float therefore inherit this operator? (No.) If so, the following function exists:
function "*" (Left: Float; Right: root_integer) return Float;
which would make the following legal:
declare X: Float; begin ... X := X * 2; -- Legal? (No.) end;
The same applies to a user-defined numeric type.
!response
Although floating point types are derived from root_real, this does not imply any inheritance of subprograms. Inheritance happens for a derived type that is declared by a derived_type_definition, by 3.4(7). For private extensions, 7.3(16) and 12.5.1(20) apply. No such rules apply to other kinds of type_definition; therefore, no inheritance takes place for such types.
Section 4 explicitly defines the predefined operators that are implicitly declared for a type, according to its class. The mechanism of inheritance is not used for this purpose.
Note that this is not the only way in which the implicit derivation from a root numeric type is different from derivation via an explicit derived_type_definition. See, for example, 3.5.4(14) and AARM 3.5.4(14.a).
!ACATS test
It would be possible to create a B-Test to insure that the mixed operators are not inherited, but it would have little value.
!appendix

!section 4.5.5(17)
!subject Operators inherited from root_real multiplying operators
!reference RM95-4.5.5(17)
!from Norman Cohen
!reference 96-5609.a Norman H. Cohen 96-6-21>>
!discussion

Consider the operators described in 4.5.5(17), such as

   function "*" (Left: root_real; Right: root_integer) return root_real;

By 3.5.6(3), Float is derived from root_real, so we would expect it to
inherit

   function "*" (Left: Float; Right: root_integer) return Float;

which would have the surprising effect of making the following legal:

   declare
      X: Float;
   begin
      ...
      X := X * 2;
   end;

By 3.5.4(14), Integer is derived from root_integer, so we would expect
it to inherit

   function "*" (Left: root_real; Right: Integer) return root_real;

which would have the somewhat less surprising--and arguably
useful--effect of allowing

   Largest_Integer_Value : constant := 1.0 * Integer'Last;

   type Fixed_Point_Type_With_Range_Of_Integer is
      delta 1.0 range 1.0*Integer'First .. 1.0*Integer'Last;

However, the effect of these declarations can be achieved by wrapping
Integer'First and Integer'Last inside Integer'Pos(...), or by declaring
universal_integer named numbers:

   Integer_First : constant := Integer'First;
   Integer_Last  : constant := Integer'Last;

Here is a line of reasoning that would allow us to deduce that ordinary
numeric types do not inherit from the operators in 4.5.5(17):  Although
the operators are declared in Standard (A.1(29,30,31)), no declarations
for root_integer and root_real appear in Standard, only comments in
A.1(11) and and A.1(20) stating that these types "are predefined".  Thus
the multiplying operators are not primitive operations of the root
numeric types.

While the MRT may have had this in mind all along, I would feel more
comfortable if it were explicitly stated in an AI.

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

!section 4.5.5(17)
!subject Operators inherited from root_real multiplying operators
!reference RM95-4.5.5(17)
!reference 96-5609.a Norman H. Cohen 96-6-21
!from Bob Duff
!reference 96-5611.a Robert A Duff 96-6-22>>
!discussion

> Consider the operators described in 4.5.5(17), such as
>
>    function "*" (Left: root_real; Right: root_integer) return root_real;
>
> By 3.5.6(3), Float is derived from root_real, so we would expect it to
> inherit
>
>    function "*" (Left: Float; Right: root_integer) return Float;

This is the hole in the argument.  There are no rules saying that all
types inherit things from their parent/ancestor.  Instead, it's all
based on syntax rules.  3.4 says that derived types declared by a
derived_type_definition inherit certain things.  (Note the use of "the
derived type", as opposed to "a derived type", in 3.4(7).)  7.3(16) and
12.5.1(20) say that more-or-less the same thing happens for [formal]
private extensions.  But there is no such rule for all types that are
derived from some parent, and in particular, there is no such rule for
Float.  Float is declared by a floating_point_whatever_it_is, and not by
a derived_type_definition.

> which would have the surprising effect of making the following legal:
>
>    declare
>       X: Float;
>    begin
>       ...
>       X := X * 2;

Illegal.  Whether that's surprising or not, I suppose, depends on your
point of view.  ;-)

>    end;
>
> By 3.5.4(14), Integer is derived from root_integer, so we would expect
> it to inherit
>
>    function "*" (Left: root_real; Right: Integer) return root_real;

No, Integer is not declared by a derived_type_definition, so it doesn't
inherit anything.

> Here is a line of reasoning that would allow us to deduce that ordinary
> numeric types do not inherit from the operators in 4.5.5(17):  Although
> the operators are declared in Standard (A.1(29,30,31)), no declarations
> for root_integer and root_real appear in Standard, only comments in
> A.1(11) and and A.1(20) stating that these types "are predefined".  Thus
> the multiplying operators are not primitive operations of the root
> numeric types.

I think root_integer and root_real *are* declared in Standard.  Luckily,
there's no need for this line of reasoning.

> While the MRT may have had this in mind all along, I would feel more
> comfortable if it were explicitly stated in an AI.

What the MRT had in mind was the syntax-based definition of what gets
inherited, as explained above, which does not apply to all types that
happen to be defined to be derived magically from some parent.  I seem
to remember some earlier versions of Ada 9X that tried to fold all the
predefined operators into the notion of inheritance, but it didn't work,
and it was uncomfortably different from the Ada 83 definition, so we
gave up on that idea.

Note also that base ranges wouldn't work right, if "type T is range
1..10;" were defined to be equivalent to "type T is new <root_integer>
range 1..10;".  Luckily, it's not.

- Bob

P.S. This seems to be a case where Pascal Leroy (whom I cc'ed) would
say, "We don't need a whole 'nother AI for this".  On the other hand,
Norman explicitly asked for an official AI ruling.

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

!section 4.5.5(17)
!subject Operators inherited from root_real multiplying operators
!reference RM95-4.5.5(17)
!reference 96-5609.a Norman H. Cohen 96-6-21
!reference 96-5611.a Robert A Duff 96-6-22
!from Norman Cohen
!reference 96-5612.a Norman H. Cohen 96-6-24>>
!discussion

 >                                    There are no rules saying that all
 > types inherit things from their parent/ancestor.  Instead, it's all
 > based on syntax rules.  3.4 says that derived types declared by a
 > derived_type_definition inherit certain things.  (Note the use of "the
 > derived type", as opposed to "a derived type", in 3.4(7).)

Oh, give me a break!  ;-)

This is obscurantism at its worst.  What is the point of even saying that
the numeric types are "implicitly derived from" the root types if this
implies nothing about inheritance of operations?  And where is there any
suggestion in the RM that types can be derived in any way other than by
derived-type declarations (which would be necessary to deduce that
"implictly derived from" can mean anything other than "declared by one or
more implicit derived-type declarations")?

 > I think root_integer and root_real *are* declared in Standard.

Do you mean you think you see declarations in A.1 of the form

   type root_integer is ...;
   type root_real is ...;

or just that that is your preferred interpretation of the statement in
A.1 that such types exist?

I certainly prefer my explanation for why the 4.5.5(17) operations are
not inherited by Integer and Float.

 > P.S. This seems to be a case where Pascal Leroy (whom I cc'ed) would
 > say, "We don't need a whole 'nother AI for this".  On the other hand,
 > Norman explicitly asked for an official AI ruling.

This is not an obvious confirmation, nor is it a purely theoretical
musing.  I had stumbled into it by writing something like

   delta 1.0 range -1.0*Integer'First .. 1.0*Integer'Last

For a while, I had convinced both myself and some GNAT implementors that
this should be legal, and we were all relieved to come up with a line of
reasoning arguing that it is not.  I find it quite plausible that others
will stumble upon it and be equally successful in bamboozling
implementors into believing that the operators are inherited, so it
seems worthwhile to document the intent of the standard.

Note that we are agreed about the desired conclusion, and the only
controversy is about which legalisms we should use to reach that
conclusion.

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

!section 4.5.5(17)
!subject Operators inherited from root_real multiplying operators
!reference RM95-4.5.5(17)
!reference 96-5609.a Norman H. Cohen 96-6-21
!reference 96-5611.a Robert A Duff 96-6-22
!reference 96-5612.a Norman Cohen
!from Bob Duff
!reference 96-5613.a Robert A Duff 96-6-24>>
!discussion

> Oh, give me a break!  ;-)
>
> This is obscurantism at its worst.

A fair criticism, perhaps, but it doesn't change the facts.  ;-)
I happen to think that it is ludicrous that (in Ada 83 and Ada 95),
"type T is range 1..10;" is called a type declaration, but it does
*not* declare a type called T.  But just because I don't like it,
doesn't mean it's false (in our little RM universe).

>...  What is the point of even saying that
> the numeric types are "implicitly derived from" the root types if this
> implies nothing about inheritance of operations?

The point is so that the basic type model and type matching rules will
work out nicely.  We want to have a class, "the class of all integer
types", rooted at root_integer, with a corresponding universal type
universal_integer.  (Note that universal_integer is sort of like
root_integer'Class, as explained in 3.4.1(6).)  This model then fits in
with the type matching rules of 8.6, plus the definitions of "derived
from", "cover", and "descendant" in 3.4.1.

The numeric classes are somewhat special, because we want to talk about
the root of the classes and corresponding universal types explicitly.
There was no need for, e.g., a root_access or universal_access type, so
access types don't bother with this stuff.

>...  And where is there any
> suggestion in the RM that types can be derived in any way other than by
> derived-type declarations (which would be necessary to deduce that
> "implictly derived from" can mean anything other than "declared by one or
> more implicit derived-type declarations")?

There's a "hint" in RM-3.5.4(14), and more hints in the AARM annotations
following that:

14   {root_integer} {Min_Int} {Max_Int} A type defined by an integer_type_
definition is implicitly derived from root_integer, an anonymous predefined
(specific) integer type, whose base range is System.Min_Int .. System.Max_
Int.  However, the base range of the new type is not inherited from root_
integer, but is instead determined by the range or modulus specified by the
integer_type_definition.  {universal_integer [partial]} {integer literals}
[Integer literals are all of the type universal_integer, the universal type
(see 3.4.1) for the class rooted at root_integer, allowing their use with the
operations of any integer type.]

        14.a   Discussion:  This implicit derivation is not considered
        exactly equivalent to explicit derivation via a derived_type_
        definition.  In particular, integer types defined via a derived_type_
        definition inherit their base range from their parent type.  A type
        defined by an integer_type_definition does not necessarily inherit
        its base range from root_integer.  It is not specified whether the
        implicit derivation from root_integer is direct or indirect, not that
        it really matters.  All we want is for all integer types to be
        descendants of root_integer.

The RM clearly says that this sort of derivation is different from the
explicit kind, in that the base range is not inherited.  The AARM
elaborates on that point, making it quite clear that this implicit
derivation is somewhat magical.  If you don't *like* that fact, I have
some sympathy, but it's true nonetheless.

>  > I think root_integer and root_real *are* declared in Standard.
>
> Do you mean you think you see declarations in A.1 of the form
>
>    type root_integer is ...;
>    type root_real is ...;
>
> or just that that is your preferred interpretation of the statement in
> A.1 that such types exist?

I can't think of any other reasonable interpretation of A.1(11):

   4   package Standard is
   ...
   11     -- The integer type root_integer is predefined.
          -- The corresponding universal type is universal_integer.

Why would this be mentioned in package Standard if the types aren't
declared there?  If you don't buy that, then how about 3.2.1(10):

10   {predefined type} The predefined types [(for example the types Boolean,
Wide_Character, Integer, root_integer, and universal_integer)] are the types
that are defined in [a predefined library package called] Standard[; this
package also includes the [(implicit)] declarations of their predefined
operators].  [The package Standard is described in A.1.]

        10.a   Ramification:  We use the term ``predefined'' to refer to
        entities declared in the visible part of Standard, to implicitly
        declared operators of a type whose semantics are defined by the
        language, to Standard itself, and to the ``predefined environment''.
        We do not use this term to refer to library packages other than
        Standard.  For example Text_IO is a language-defined package, not a
        predefined package, and Text_IO.Put_Line is not a predefined
        operation.

> I certainly prefer my explanation for why the 4.5.5(17) operations are
> not inherited by Integer and Float.

As explained above, I don't think it works.  Now, if root_integer is
declared in Standard, and if you go with the idea that implicit
derivation works just like explicit derivation, then we have to wonder
whether the operator you mentioned is user-defined or predefined, since
only user-defined operators get inherited.  I think "predefined" makes
the most sense, but I can't find any compelling justification for that
in the RM wording.  I would prefer not to have to answer that question.

> This is not an obvious confirmation,

To me, it seems like an obvious confirmation (though I don't blame you
for being surprised by it).  To you and Pascal, it is apparently quite
non-obvious.  That's why I'm a bit nervous about having been handed the
responsibility of deciding what's "obvious" -- it's too easy for me to
"cheat" by knowing what I meant to write.  (Actually, I think Tucker
wrote 3.5.4(14,14.a), but still....  I do remember discussing the
wording of that particular paragraph explicitly with Tucker.)  I'm
inclined to say that if Norman Cohen demands an official AI ruling, then
he should get one.  I hope all ARG members will review my decisions as
to which issues should be seriously and promptly considered by the ARG.

>...nor is it a purely theoretical
> musing.  I had stumbled into it by writing something like
>
>    delta 1.0 range -1.0*Integer'First .. 1.0*Integer'Last
>
> For a while, I had convinced both myself and some GNAT implementors that
> this should be legal, and we were all relieved to come up with a line of
> reasoning arguing that it is not.  I find it quite plausible that others
> will stumble upon it and be equally successful in bamboozling
> implementors into believing that the operators are inherited, so it
> seems worthwhile to document the intent of the standard.

OK.

> Note that we are agreed about the desired conclusion, and the only
> controversy is about which legalisms we should use to reach that
> conclusion.

Right.  It's nice when two parties can agree on what they're arguing
about, even if they don't agree on the right answer!

- Bob

P.S. I talked about root_integer above.  I didn't look up root_real and
root_fixed, but I assume their wording is similar.

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

Questions? Ask the ACAA Technical Agent