37

Found an interesting issue that following code runs with a different result:

char c = 'a';

c += 'a';   //passed
c = c + 'a'; //Cannot implicitly convert type 'int' to 'char'. An explicit conversion exists (are you missing a cast?)

Is there any difference between a += b and a=a+b, or just compiler's code check missed it?

My point is why char += char can pass the code check while char = (char+char) considered char = int?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
喵喵喵
  • 691
  • 7
  • 12
  • what happens when you say `c = c + ((char)1)`? – Psi Apr 06 '17 at 11:40
  • Well, `char + char` is `int` so `c + (char)1` is `int` which should be converted to `char`: `c = (char) (c + 1);` or `c = (char) (c + (char)1);` – Dmitry Bychenko Apr 06 '17 at 11:42
  • You get similar from this : short x = 1; x = x+(short)1; or x = x+1; - you need to explicitly say x = (short)(x+1). Integral arithmetic is done to integer size, regardless of the original operands. – PaulF Apr 06 '17 at 11:43
  • 1
    I knew char + char outputs an integer,my point is why c +=(char)1 can pass the code check – 喵喵喵 Apr 06 '17 at 11:44
  • 2
    Surely if it didn't, then the += & other assignment operators would be pointless for other than ints. – PaulF Apr 06 '17 at 11:46
  • @PaulF most implementation of the + operator return the type of the addends. ie: TimeSpan + TimeSpan : TimeSpan Therefor TimeSpan += TimeSpan works as well. I'm not sure why you expect the + operator to always return an int? – Patrick Huizinga Apr 06 '17 at 14:46
  • @PatrickHuizinga: What I said was that for _"integral"_ types (which includes char & short, but not TimeSpan) the result would be int not for all types. OPs original question was why += works differently to +. – PaulF Apr 06 '17 at 15:15
  • [Integer summing blues, short += short problem](http://stackoverflow.com/q/4343624/995714) – phuclv Apr 06 '17 at 15:16
  • The fact that a character constant like `'a'` has type `int` is a legacy of K&R C. It made sense on the PDP-10. And conversion from `int` to `char` is a narrowing conversion that could lose information. So C# makes you say, *Yes, I’m sure I want to do that.* – Davislor Apr 06 '17 at 21:04
  • @PaulF ah right, I read you 2nd comment without the context of the first. – Patrick Huizinga Apr 07 '17 at 07:52

4 Answers4

44

C# Specification, Section 7.17.2 Compound assignment:

An operation of the form x op= y is processed by applying binary operator overload resolution (§7.3.4) as if the operation was written x op y. Then,

...

• Otherwise, if the selected operator is a predefined operator, if the return type of the selected operator is explicitly convertible to the type of x, and if y is implicitly convertible to the type of x or the operator is a shift operator, then the operation is evaluated as x = (T)(x op y), where T is the type of x, except that x is evaluated only once

And that's exactly the situation we have here. The return type of the operation is int but the types of x and y are both char, and so an extra cast is automatically inserted for us.

(I believe this rule exists because there's nowhere for you to be able to insert an explicit cast yourself and it's kind of "expected" to work, especially in cases where x and y are the same type)

Community
  • 1
  • 1
Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
9

In the second case it is the assignment that is failing, not the calculation itself. If you explicitly cast the result in the second line to a char it works fine and indeed the following three lines generate identical IL:

    c += (char)1;
    c = (char)(c + (char)1);
    c = (char)(c + 1);

So yes. There is a difference.

Note in the third line I didn't bother casting the 1 to char since the calculation will just convert it back to an int anyway.

Chris
  • 27,210
  • 6
  • 71
  • 92
4

The resulting type of += is char in this case and the resulting type of c + (char)1 is int.

The following code prints:

o1 System.Char o2 System.Int32

    public static void Main(string[] args)
    {
        char c = 'a';

        object o1 = c += (char)1;
        object o2 = c + (char)1;

        WriteLine("o1 " + o1.GetType());
        WriteLine("o2 " + o2.GetType());
     }
Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
2

To put Damien's answer in simpler terms:
Compound operators (e.g. +=, -= etc.) automatically cast the result to the targeted type (if possible). Therefore c += 'a' works, because it is evaluated as c = (char)(c + 'a').

In this case, the conversion is necessary, because the return-type of arithmetic operations between chars is int (which is why c = c + 'a' does not compile, as it is missing the cast above).

DerClef
  • 141
  • 3