[comp.lang.ada] Implicit conversion?

eachus@mbunix.mitre.org (Robert Eachus) (03/09/89)

In article <5678@sdcrdcf.sm.unisys.com> steve@sm.unisys.com (Steven Holtsberg) writes:
>
>In the following program, some implicit type conversion apparently
>takes place.  However, looking at the Standard, I cannot see where
>this should happen.
...
>with SYSTEM; use SYSTEM;
>
>procedure example is
>  x: tiny_integer;
>begin
>  x:= MAX_INT - MAX_INT;
>end example;

>With the Verdix xompiler, this program compiles and executes normally,
>so, there is apparently a convertion of 0 to TINY_INTEGER.

     No, there is an implicit conversion of MAX_INT to tiny_integer.

 >"An implicit conversion of an operand of type universal_integer
 >to another integer type...can only be applied if the operand is
 >either a numeric literal, a named number, or an attribute; such
 >an operand is called a convertible universal operand in this section.
 >An implicit conversion of a convertible universal operand is applied
 >if and only if the innermost complete context (see 8.7) determines
 >a unique (numeric) target type for the implicit conversion, and there
 >is no legal interpretation of this context without this conversion."

 >From 8.7, the innermost complete context of SYSTEM.MAX_INT in the above
 >example is the assignment statement
 >  x := MAX_INT - MAX_INT; -- corrected per following message...

      True, and this complete context determines that the unique
 target type for the conversion is tiny_integer.  If there were a
 visible declaration: "function "-" (L,R: Integer) return
 tiny_integer" then the implicit conversions would be illegal.

 >What the Verdix compiler is apparently doing is figuring out that
 >MAX_INT - MAX_INT is zero (at compile-time)...

      True, but it is not converting the result to zero, it is using
 the "-" operator for tiny_integer and doing the conversion first.
 This is legal, and must be legal, on all implementations.  However,
 it may raise an exception during execution.  The reason Verdix
 doesn't raise CONSTRAINT_ERROR or NUMERIC_ERROR is more subtile.

      If you look at 3.5.5(1) you find that implicit conversion to an
 integer type is a basic operation of the type.  In 11.6(3) (but read
 all of 11.6) "...freedom is left to an implementation for reordering
 actions...that are...basic operations other than assignments.  This
 freedom is left, as defined below, even where the execution...may
 propagate a predefined exception."

      The note in 11.6(9) makes it perfectly clear that execptions
 need not be raised for implicit conversions from universal types.  As
 for the subtraction, 4.5(7) says: "A predefined operation that
 delivers a result of an integer type (other than universal_integer)
 can only raise the exception NUMERIC_ERROR if the mathematical result
 is not a value of the type."  Zero is a value of tiny_integer, so the
 subtraction can not raise an exception.

 >At I right, or am I wrong?

      Wrong, but the language may be wrong too.  AI-315, which has not
 yet been approved, discusses the fact that 11.6 may give too much rope
 to clever compilers.  When we figure out a rule that does not inhibit
 useful optimizations like constant folding, but allows a user to
 insure that certain out-of-range expressions always raise an
 exception, the rules may change.



					Robert I. Eachus

with STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...

stt@ada-uts (03/09/89)

W.r.t.: X := MAX_INT - MAX_INT;
You are correct that formally the conversion to
tiny integer takes place at the leaves of the expression,
however 4.5:7 in the LRM states:
  The predefined operations on integer types either yield the
  mathematically correct result or raise the exception NUMERIC_ERROR.

Hence it is perfectly legal to perform intermediate calculations
with predefined operators using more accuracy than the declared type.
I suspect that most Ada compilers will evaluate "static" expressions
(see 4.9 for definition) with infinite precision, since
they are required to evaluate all static *universal* expressions
exactly.

S. Tucker Taft
Intermetrics, Inc.
Cambridge, MA  02138

steve@dim.sm.unisys.com (Steven Holtsberg) (03/14/89)

In article <46125@linus.UUCP> eachus@mbunix.mitre.org (Robert I. Eachus) writes:
>>procedure example is
>>  x: tiny_integer;
>>begin
>>  x:= MAX_INT - MAX_INT;
>>end example;
|
|     ... there is an implicit conversion of MAX_INT to tiny_integer.
|
|      ... but it is not converting the result to zero, it is using
| the "-" operator for tiny_integer and doing the conversion first.
| This is legal, and must be legal, on all implementations.  However,
| it may raise an exception during execution.  The reason Verdix
| doesn't raise CONSTRAINT_ERROR or NUMERIC_ERROR is more subtile.

I do not see how MAX_INT, (2147483647 in this implementation) can be
converted to TINY_INTEGER (-128 .. 127).  I believe that
the "-" operator for TINY_INTEGER is doing what 11.6(6) allows it to do,
that is, "...use the operation of a type that has a range wider that that of
the base type of the operands..."

| In 11.6(3) (but read
| all of 11.6) "...freedom is left to an implementation for reordering
| actions...that are...basic operations other than assignments.  This
| freedom is left, as defined below, even where the execution...may
| propagate a predefined exception."

I don't understand what freedom to reorder actions has to do with this example.

rracine@ajpo.sei.cmu.edu (Roger Racine) (03/18/89)

With respect to 

X := MAX_INT - MAX_INT;

Why would it be necessary to convert MAX_INT to anything?  There exists a
predefined "-" operation which takes two universal_integers and returns
universal_integer.  Then one is left with 

X := 0;

Implicit type conversion on the 0 works fine, and no errors occur.

On the other hand, if the implicit type conversion did take place, I think
the LRM is clear that CONSTRAINT_ERROR should occur (4.6 para 12).

4.6 para 15 states:
"An implicit conversion ... is applied if and only if the innermost complete
context (see 8.7) determines a unique ... target type for the implicit
conversion, and there is no legal interpretation of this context without
this conversion."

While the innermost complete context, which is the statement, does determine
a unique target type, I would maintain that there is a legal interpretation
without the conversion.  The subtraction can be seen as a universal
expression, which is then converted.

I do NOT see how one can consider the implicit conversion of MAX_INT to be
an "intermediate result" of a predefined operation.  I always took that
phrase to mean "once the operations started, if the expression has more
than one operation, NUMERIC_ERROR does not need to be raised even if one
of the operations gives a result which is outside the range of the base
type."  

Please help me understand why an implementation should be allowed to
raise ANY exception.

steve@sea.sm.unisys.com (Steven Holtsberg) (03/18/89)

In article <474@ajpo.sei.cmu.edu> rracine@ajpo.sei.cmu.edu (Roger Racine) writes:
>With respect to 
>
>X := MAX_INT - MAX_INT;
>
>Why would it be necessary to convert MAX_INT to anything?  There exists a
>predefined "-" operation which takes two universal_integers and returns
>universal_integer.  Then one is left with 
>
>X := 0;
>
>Implicit type conversion on the 0 works fine, and no errors occur.
>
I don't believe that an implicit type conversion can be performed on the 0.
Although a similar rule is not given for implicit type conversions, the
rule for explicit type conversions says that the "expression given as the
operand" is evaluated and the conversion is done on the "resulting value."
In this case, 0 is not an expression in this assignment statement; it is
the value of the expression MAX_INT - MAX_INT, which is not a convertible
universal operand.

Now, I assume the intent is that the operand of an implicit type conversion
must also be an expression.  However, the ARM does not explicitly state this
(no pun intended!).

What do the experts think?