Coercion in Expressions
One of the design decisions concerning arithmetic expressions is whether an operator can have operands of different types. Languages that allow such expressions, which are called mixed-mode expressions, must define conventions for implicit operand type conversions because computers do not have binary operations that take operands of different types.
Type conversions explicitly requested by the programmer are referred to as explicit conversions, or casts, not coercions. Although some operator symbols may be overloaded, we assume that a computer system, either in hardware or in some level of software simulation, has an operation for each operand type and operator defined in the language.For overloaded operators in a language that uses static type binding, the compiler chooses the correct type of operation on the basis of the types of the operands. When the two operands of an operator are not of the same type and that is legal in the language, the compiler must choose one of them to be coerced and supply the code for that coercion. In the following discussion, the coercion design choices of several common languages are examined.
Language designers are not in agreement on the issue of coercions in arithmetic expressions. Those against a broad range of coercions are concerned with the reliability problems that can result from such coercions, because they reduce the benefits of type checking. Those who would rather include a wide range of coercions are more concerned with the loss in flexibility that results from restrictions. The issue is whether programmers should be concerned with this category of errors or whether the compiler should detect them.
As a simple illustration of the problem, consider the following Java code:
float b, c, d;
. . .
d = b * a;
Assume that the second operand of the multiplication operator was supposed to be c, but because of a keying error it was typed as a. Because mixed-mode
expressions are legal in Java, the compiler would not detect this as an error. It would simply insert code to coerce the value of the int operand, a, to float. If mixed-mode expressions were not legal in Java, this keying error would have been detected by the compiler as a type error.
Because error detection is reduced when mixed-mode expressions are allowed, Ada allows very few mixed type operands in expressions. It does not allow mixing of integer and floating-point operands in an expression, with one exception: The exponentiation operator, **, can take either a floating-point or an integer type for the first operand and an integer type for the second operand. Ada allows a few other kinds of operand type mixing, usually related to subrange types. If the Java code example were written in Ada, as in
A : Integer;
B, C, D : Float;
. . .
C := B * A;
then the Ada compiler would find the expression erroneous, because Float and Integer operands cannot be mixed for the * operator.
ML and F# do not coerce operands in expressions. Any necessary conversions must be explicit. This results in the same high level of reliability in expressions that is provided by Ada. In most of the other common languages, there are no restrictions on mixed-mode arithmetic expressions. The C-based languages have integer types that are smaller than the int type. In Java, they are byte and short. Operands of all of these types are coerced to int whenever virtually any operator is applied to them. So, while data can be stored in variables of these types, it cannot be manipulated before conversion to a larger type. For example, consider the following Java code:
byte a, b, c;
. . .
a = b c;
The values of b and c are coerced to int and an int addition is performed. Then, the sum is converted to byte and put in a. Given the large size of the memories of contemporary computers, there is little incentive to use byte and short, unless a large number of them must be stored.