3

The following code prints UInt32:

var myUint = 1U;
Console.WriteLine(myUint.GetType().Name);

As per this SO answer I wanted to see what would happen if you try to use the U literal suffix with a compile-time negative number. This code (changing1U to -1U) prints Int64 (long):

var myUint = -1U;
Console.WriteLine(myUint.GetType().Name);

I thought it would just be a compile time error, but instead returns a long with the value -1 - what is going on? Why does the compiler do this??

Sam Watson
  • 31
  • 2
  • 1
    Unsigned values cannot be negative. The C# compiler punts for the next larger signed integral type to avoid overflow. – Hans Passant Oct 11 '18 at 08:42

2 Answers2

3

The minus sign is not a part of the integer literal specification. So when you write var x = -1U, the following rules are applied by the compiler:

If the literal is suffixed by U or u, it has the first of these types in which its value can be represented: uint, ulong.

So that's the 1U part becoming a uint / UInt32, so far conforming to your expectations.

But then the minus is applied:

For an operation of the form -x, unary operator overload resolution (§7.3.3) is applied to select a specific operator implementation. The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. The predefined negation operators are:

  • Integer negation:

    int operator -(int x);

    long operator -(long x);

[...]

If the operand of the negation operator is of type uint, it is converted to type long, and the type of the result is long.

So the type of the expression -1U is long, as per the C# specification. This then becomes the type of x.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

Obviously -1U cannot be stored as a uint. Since you use var, the compiler deduces the type to hold the value. Since you want to hold -(1 as unsigned integer), the compiler decides to store it as long.

You would get a compile time error if you defined your type explicitly:

uint myUint = -1U;

Michal B.
  • 5,676
  • 6
  • 42
  • 70
  • It's the compiler that *deduces* the correct type. Not the framework per se. – Damien_The_Unbeliever Oct 11 '18 at 08:41
  • 1
    _"Since you use var, the framework decides on the datastructure to use to hold the value"_ - that doesn't have to do with `var`. The expression after the assignment operator isn't influenced by the `var` declaration. – CodeCaster Oct 11 '18 at 08:41
  • CodeCaster, var is used to define the type implicitly. The compiler decides on the type based on the value. – Michal B. Oct 11 '18 at 08:42
  • The type of the _variable_ (`myUint`), not the type of the literal. – CodeCaster Oct 11 '18 at 08:42
  • Yes, and that is why the type of the variable becomes long. – Michal B. Oct 11 '18 at 08:43
  • I prefer deduce over decide just because it's really not got a lot of *choice* here. The expression to the right of the assignment must have a type that the compiler knows, irrespective of the fact that in this circumstance, it's also being used to type a variable. – Damien_The_Unbeliever Oct 11 '18 at 08:43
  • @Damien_The_Unbeliever It does sound better. Though, I am not a native, so I am not coming quickly with these words. Feel free to edit and correct the wording/grammar :-) – Michal B. Oct 11 '18 at 08:44
  • Actually, in some very very specific cases, the compilation of the expression to the right of the assignment operator will in fact be influenced by `var`. Try `FormattableString x = $"{DateTime.Now}";`, inspect the compiled code, then change `FormattableString` to `var` and inspect the compiled code. Not very useful or interesting though, and completely besides the point related to the topic here. – Lasse V. Karlsen Oct 11 '18 at 10:24