I am trying to figure out why casts are required in the following examples:
bool test = new Random().NextDouble() >= 0.5;
short val = 5;
// Ex 1 - must cast 0 to short
short res = test ? 5 : 0; // fine
short res = test ? val : 0; // error
short res = test ? val : (short)0; // ugly
// Ex 2 - must cast either short or null to short?
short? nres = test ? val : null; // error
short? nres = test ? (short?)val : null; // ugly
short? nres = test ? val : (short?)null; // ugly
short? nres = test ? val : default(short?); // ugly
The first example just seems crazy to me. If short i = 0;
compiles, why can't the compiler implicitly treat the 0 (or any other valid short
value) as a short
in the above code?
The second example makes more sense to me. I understand that the compiler is unable to determine the type of the expression on the right side of the =
, but IMO it should take nullable types into account when doing so.
I'd like to understand if there is actual reasoning behind these compiler errors.
The expression test ? val : 0
compiles just fine. You get an error in this line, because the type of this expression is int
and you're trying to assign it to a short
variable. That requires an explicit cast. From C# language spec:
If an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
Another question is why, for example, a literal 0
can be assigned to a short
variable without a cast:
short i = 0;
And a result of ternary operator has to be cast:
bool test = new Random().NextDouble() >= 0.5;
short val = 5;
short i = (short)(test ? val : 0);
The reason is that first assignment is evaluated at compile-time, because it consists only of constants. In such case, the implicit constant expression conversion rules apply:
• A constant-expression (§7.19) of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type.
The ternary operator can also be evaluated at compile time if all operands are constants:
short i = true ? 0 : int.MaxValue;
In any other case, the stricter runtime conversion rules apply. All 3 statements below give compile errors:
int intVal = 0;
short shortVal = 0;
bool boolVal = true;
short i = true ? 0 : intVal;
short j = true ? shortVal : 0;
short k = boolVal ? 0 : 0;
For reference you can see Eric Lippert's comments.
The second example would require treating Nullable<>
as a special case, like you already noticed.