4

I stumbled upon the behavior that bitwise or arithmetic operations are not allowed on primitive types smaller than 32 bit, but the respective assignment operations are in fact allowed:

short BitwiseAnd(short a, short b) { return a & b; }         // error
short BitwiseAndAssignment(ref short a, short b) { a &= b; } // works

short Add(short a, short b) { return a + b; }                // error
short AddAssignment(ref short a, short b) { a += b; }        // works

The same behavior holds for other short primitive types like byte, sbyte, and ushort.

I understand that arithmetic and logical operations are defined for 32-bit and larger types (int, long...) because it's what the processor provides (see this question), and shorter types are widened and can be casted back to 8 or 16 bit. However, is there a reason why this would work in an assignment operator? First I assumed that behind the scenes, the shorts are casted to int, but then you would have an assignment/return value short value = (some int), which should yield an error since the cast is not implicit.

On a different note: I tried out some code in Visual Studio's immediate window, but there, a lot more code seems to work. The immediate window probably does some implicit casting which would usually be explicit. E.g., short a = (int)5; is allowed in the immediate window. So that's not helping.

Community
  • 1
  • 1
hschmauder
  • 308
  • 1
  • 9
  • 2
    short Add(short a, short b) { return (short)(a + b); } – sujith karivelil Sep 17 '15 at 09:29
  • 2
    http://stackoverflow.com/questions/4343624/integer-summing-blues-short-short-problem – Matteo Umili Sep 17 '15 at 09:42
  • 1
    re `short a = (int)5;` in the immediate window - that works in regular C# too; here the values `5` and `(int)5` can be processed and understood entirely at compile time as constant expressions; the compiler checks that these constant expressions don't overflow, etc, and allows it. Conversely, if you do `short a = (int)50000000;`, the compiler breaks at **compile time** (not runtime) with a [CS0031](https://msdn.microsoft.com/en-us/library/879y0b2y(v=vs.90).aspx). – Marc Gravell Sep 17 '15 at 09:47
  • I see, thanks! I didn't notice the compile-time constant substitution. It's just different because of the syntactic context, which made it work in the immediate window but not in my actual code (as it can't be replaced by a constant expression there). – hschmauder Sep 17 '15 at 11:45

2 Answers2

2

The real error is due to implicit conversion of smaller integral types to int when you are doing operations on them.

When you have a & b where a and b are shorts, they both are converted to int and the & operator applies and the result will be of type int so you can not return int as short in your method declaration. a simple cast will solve the problem. (short)(a & b).

short BitwiseAnd(short a, short b) { return (short)(a & b); }  //no error!

When you have

short BitwiseAndAssignment(ref short a, short b) { a &= b; }

compiler will generate the cast for you , if not you can not ever use these kind of operators (+=, *=, ... ) on smaller types than int.


What happens under the hood??

short a = 1;
short b = 2;

short c = a + b; //error! 

Why? because + operator does not have an overload to receive two short parameter. Since implicit conversion between short and int exists then the method resolution will choose the overload that has two int as input parameters. so it will cast a and b to int and then call the chosen overload which returns an int. Because it returns an int you can not store it in a short variable so you need to cast it explicitly.

short c = (short)(a + b)//this will work
Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74
1

However, is there a reason why this would work in an assignment operator?

Yes: because otherwise the assignment operator could never work for these types - there would be no syntax that allowed it to work. The expectation of a += b or a &= b is clear, so the conversion is performed automatically.

With a + b or a & b, as you already note: this is widened for performance reasons; syntax exists to put it back, specifically (short)(a+b) etc.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Can you expand this *expectation* thing? Because for my expectation, when the `+` operator is not defined, I definintely would not assume that `+=` is defined. So I would *expect* that there is no syntax to make it work. – hschmauder Sep 17 '15 at 09:46
  • 1
    @hschmauder in C#, assignment operators **cannot** be explicitly overloaded; they are implicitly overloaded using the binary operators. Meaning: if `+` is supported, so is `+=`, interpreted as `a += b;` => `a = (AType)(a + b);` – Marc Gravell Sep 17 '15 at 09:52
  • "widened for performance reasons" seems like a dubious claim to me. I doubt the impact is big, especially since the JITter could widen transparently in many situations. – CodesInChaos Sep 17 '15 at 10:21