Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ternary operator behaviour inconsistency [duplicate]

Following expression is ok

short d = ("obj" == "obj" ) ? 1 : 2;

But when you use it like below, syntax error occurs

short d = (DateTime.Now == DateTime.Now) ? 1 : 2;

Cannot implicitly convert type 'int' to 'short'. An explicit conversion exists (are you missing a cast?)

Can anyone explain why this is so?

Is there a difference between comparing string-to-string and datetime-to-datetime in a ternary operator, why?

I would be grateful if you could help me.

like image 748
Mehmet Kasalak Avatar asked Feb 14 '14 13:02

Mehmet Kasalak


3 Answers

C# language specification, version 5, section 6.1.9:

An implicit constant expression conversion permits the following conversions:

  • 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.

Your first example is a constant expression, because it can be evaluated at compile time. But see section 7.19 for more details:

Only the following constructs are permitted in constant expressions:

  • Literals (including the null literal).

[...]

  • The predefined +, –, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators, provided each operand is of a type listed above.
  • The ?: conditional operator.
like image 180
Damien_The_Unbeliever Avatar answered Oct 18 '22 21:10

Damien_The_Unbeliever


I believe in the first case the compiler knows that the strings are equal at compile time and therefore optimizes the code to just:

short d = 1;

That works because 1 can be assigned to short variable.

In the second case optimization cannot happen because compiler cannot infer equality at compile time, so it leaves:

short d = (DateTime.Now == DateTime.Now) ? (long)1 : (long)2;

This will compile:

short d = (DateTime.Now == DateTime.Now) ? (short)1 : (short)2;

IL (LinqPad) for call short d = ("obj" == "obj" ) ? 1 : 2;:

IL_0001:  ldc.i4.1    
IL_0002:  stloc.0     // d
like image 44
Jakub Konecki Avatar answered Oct 18 '22 23:10

Jakub Konecki


"obj" == "obj" can be resolved at compile time; compiler treats it as

short d = 1;

namespace ConsoleApplication1 {
  class Program {
    static void Main(string[] args) {
      short d = ("obj" == "obj") ? 1 : 2;
    }
  }
}

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
 // Code size       4 (0x4)
 .maxstack  1
 .locals init ([0] int16 d)
 IL_0000:  nop
 IL_0001:  ldc.i4.1
 IL_0002:  stloc.0
 IL_0003:  ret
 } // end of method Program::Main

DateTime.Now == DateTime.Now can't be resolved at compile time and throws an error.

like image 44
Ondrej Svejdar Avatar answered Oct 18 '22 23:10

Ondrej Svejdar