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?