Implicit conversion rules AI-00136/05 1
88-11-04 ra WA
| !standard 04.06 (15) 88-11-04 AI-00136/05
!class ramification 83-11-07
| !status approved by WG9 88-10-28
!status ARG-approved 88-05-10 (reviewed)
!status ARG-approved (13-0-0) 88-01-19 (pending editorial review)
!status work-item 87-07-10
!status received 83-11-07
| !references 83-00189, 83-00190, 83-00191, 83-00193, 83-00959
!topic Implicit conversion rules
!summary 87-07-13
An implicit conversion of a convertible universal operand is applied if and
only if the innermost enclosing 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.
| !question 88-11-04
4.6(15) defines implicit type conversions:
Apart from the explicit type conversions, the only allowed form
of type conversion is the implicit conversion of a value of the
type universal_integer or universal_real into another numeric
type. An implicit conversion of an operand of type universal_
integer to another integer type, or of an operand of type
universal_real to another real 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.
Consider the following example:
function F (X : BOOLEAN) return INTEGER is
begin return 66; end;
function "<" (X, Y : INTEGER) return INTEGER is
begin return 77; end;
package INTERNAL1 is
X : INTEGER := F (5 < 5); -- OK
-- uses F (BOOLEAN), "<" (univ_int, univ_int) --> BOOLEAN
end INTERNAL1;
function F (X : INTEGER) return INTEGER is
begin return 88; end;
Implicit conversion rules AI-00136/05 2
88-11-04 ra WA
package INTERNAL2 is
X : INTEGER := F (5 < 5); -- ambiguous? (no)
-- uses F (BOOLEAN), "<" (univ_int, univ_int) --> BOOLEAN
-- or F (INTEGER), "<" (INTEGER, INTEGER) --> INTEGER
-- along with implicit conversion univ_int to INTEGER
end INTERNAL2;
Is the line marked "ambiguous?" intended to be:
a) ambiguous, and hence illegal?
b) unambiguous and legal, with the single interpretation being
F (BOOLEAN), "<" (univ_int, univ_int) --> BOOLEAN
as determined by the program and the particular complete
context?
c) unambiguous and legal, with the single interpretation being
F (INTEGER), "<" (INTEGER, INTEGER) --> INTEGER
as determined by the program and the particular complete
context?
4.6(15) seems to imply that the answer is (b). This might not be what the
programmer wanted in the above example when, having taken such trouble to
define "<" (INTEGER, INTEGER) --> INTEGER, the program compiles without
complaint, but uses "<" (univ_int, univ_int) --> BOOLEAN instead at run time.
Thus, it seems that answer (a) would be better in this situation.
In fact, the following rearrangement of the above example is even more likely
to be confusing to the programmer:
function F (X : INTEGER) return INTEGER is ... end F;
| function "<" (X, Y : INTEGER) return INTEGER is ... end "<";
...
X : INTEGER := F (5 < 5); -- OK
-- uses F (INTEGER), "<" (INTEGER, INTEGER) --> INTEGER
-- along with implicit conversion univ_int to INTEGER
...
use PKG; -- where PKG contains F (BOOLEAN) --> INTEGER
...
X : INTEGER := F (5 < 5); -- ambiguous? (no)
-- uses F (BOOLEAN), "<" (univ_int, univ_int) --> BOOLEAN
-- or F (INTEGER), "<" (INTEGER, INTEGER) --> INTEGER
-- along with implicit conversion univ_int to INTEGER
| !response 88-11-04
The last sentence of 4.6(15) clearly says that since there is an
interpretation of line "ambiguous?" that does not use implicit conversion,
any interpretation that does use implicit conversion is ignored. Since only
Implicit conversion rules AI-00136/05 3
88-11-04 ra WA
one interpretation remains, it is chosen. Thus, the answer is (b) for both
examples, namely, that the line is unambiguous and legal, and the
interpretation is:
-- uses F (BOOLEAN), "<" (univ_int, univ_int) --> BOOLEAN
As to whether or not this is what a user expects, there was extensive
consideration given to the treatment of implicit conversions during the
language design. This analysis showed that no matter what rule was chosen,
some users might not get what they expect. It is in any case bad practice to
overload a relational operator with such a confusing meaning.
4.6(15) applies not only to cases where one of the possible interpretations
has no implicit conversions at all. It also applies to cases where all
interpretations require implicit conversions, but only one set of implicit
conversions yields an unambiguous interpretation. This is illustrated by the
following examples.
-- Example 1
procedure P (X : INTEGER; Y : BOOLEAN) is ... end P;
procedure P (X : BOOLEAN; Y : INTEGER) is ... end P;
function "<" (X, Y : INTEGER) return INTEGER is ... end "<";
...
P (5 < 4, 6 < 7); -- is overloading resolvable? (no)
| There are two possible interpretations of P (5 < 4, 6 < 7). Each of them
requires implicit conversion of two of the universal integer literals (either
5 and 4 or 6 and 7). Hence, with reference to 4.6(15), for each of the
implicit conversions it is the case that there is another legal
interpretation of the complete context without "this conversion." Therefore
no implicit conversion can be applied and the call is illegal. Similarly,
consider:
-- Example 2
procedure P (X : INTEGER; Y : INTEGER; Z : BOOLEAN) is ... end P;
procedure P (X : BOOLEAN; Y : INTEGER; Z : INTEGER) is ... end P;
function "<" (X, Y : INTEGER) return INTEGER is ... end "<";
...
P(5 < 4, 6 < 7, 1 < 2); -- is overloading resolvable? (no)
There are two possible interpretations of P(5 < 4, 6 < 7, 1 < 2). In this
case 6 and 7 will be implicitly converted to INTEGER because there are no
legal interpretations of the complete context without these conversions. For
the remaining potential implicit conversions (5 and 4 or 1 and 2) the
reasoning of example 1 applies. Hence, the call is illegal. Finally,
consider:
Implicit conversion rules AI-00136/05 4
88-11-04 ra WA
-- Example 3
procedure P (X : INTEGER; Y : BOOLEAN) is ... end P;
procedure P (X : INTEGER; Y : INTEGER) is ... end P;
function "<" (X, Y : INTEGER) return INTEGER is ... end "<";
...
P(5 < 4, 6 < 7); -- is overloading resolvable? (yes)
The literals 5 and 4 are implicitly converted to INTEGER because there are no
legal interpretations of the complete context without these conversions.
However, the literals 6 and 7 are not implicitly converted (and remain
universal integers) because there is a legal interpretation of the complete
context without these conversions (use the first P and the predefined "<" for
universal integer in 6 < 7). Therefore, the call is legal (unambiguous) and
requires only the implicit conversion of 5 and 4.
The above reasoning agrees with the expected interpretation of expressions
like X'LENGTH = 2**3, where the "**" operator requires the right operand to
be an INTEGER (causing 3 to be implicitly converted to INTEGER for all legal
interpretations of this expression, assuming the user has not overloaded
"**"). The rule of 4.6(15) prevents additional implicit conversions (of 2 and
X'LENGTH), so the "=" operator is the one for universal_integer -- not for
some other integer types whose scopes include this expression.