7

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.

drew.cuthbert
  • 1,005
  • 1
  • 9
  • 21
  • 1
    Possible duplicate of [How to use C#'s ternary operator with two byte values?](http://stackoverflow.com/questions/1890390/how-to-use-cs-ternary-operator-with-two-byte-values) – Joseph Nields Oct 13 '15 at 17:47
  • 1
    http://stackoverflow.com/questions/858080/nullable-types-and-the-ternary-operator-why-is-10-null-forbidden – Joseph Nields Oct 13 '15 at 17:47
  • 2
    Read [this comment](http://stackoverflow.com/questions/1890390/how-to-use-cs-ternary-operator-with-two-byte-values#comment1808048_1890400) that Eric Lippert made on a similar question. Basically it's _technically_ possible but it could lead down a rabbit hole that makes the cost not worth the effort of designing, building, testing, documenting, and shipping the feature. – D Stanley Oct 13 '15 at 18:10

1 Answers1

6

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.

Community
  • 1
  • 1
Jakub Lortz
  • 14,616
  • 3
  • 25
  • 39
  • I guess what I am asking is why in the world would the type of `test ? val : 0` be `int` since `val` is a `short`? Or in other words, why would `0` be considered an `int` rather than a `short` in this context? The same way you don't have to write `short i = (short)0;`, you shouldn't have to use a cast in the conditional operator. – drew.cuthbert Oct 13 '15 at 21:00
  • The literal `0` is an `int`, so the compiler would have to make an extra check to see if it's in correct range for a `short`. It's simple for `short i = 0;`, more complicated for ternary operator. You can read [Eric Lippert's explanation](http://stackoverflow.com/questions/1890390/how-to-use-cs-ternary-operator-with-two-byte-values#comment1808048_1890400). (If you don't know - he used to be in C# design committee, so he's a first-hand source) – Jakub Lortz Oct 13 '15 at 21:13
  • 1
    @andrew.cuthbert The main difference is that `short i = 0;` is evaluated at compile time, the ternary operator (with a non-const condition) at runtime. – Jakub Lortz Oct 13 '15 at 21:32
  • Ah, the combination of Lippert's explanation and your note about compile time vs runtime made me see the light. Thanks! Can you edit your answer to include compile time vs runtime? Then I will mark it accepted. – drew.cuthbert Oct 13 '15 at 21:43