tags:

views:

149

answers:

3

I have the following code:

foreach (byte b in bytes)
{
    byte inv = byte.MaxValue - b;
    // Add the new value to a list....
}

When I do this I get the following error:

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

Each part of this statement is a byte. Why does C# want to convert the byte.MaxValue - b to an int?

Shouldn't you be able to do this some how without casting? (i.e. I don't want to have to do this: byte inv = (byte) (byte.MaxValue - b);)

+4  A: 

According to the C# Language Reference:

because the arithmetic expression on the right-hand side of the assignment operator evaluates to int by default.

The reason for this could be because your processor is going to be faster at accessing a 4-byte memory address than a 1-byte memory address, so arithmetic operators are defined to work on 4-byte operands.

Bill the Lizard
I guess the question is why? When I do `int-int` it does not result in an `int64`. Why auto-promote the type when it is `byte-byte`?
Vaccano
@Vaccano: My guess is so that arithmetic operators only have to be defined to work with certain length operands (4-byte and 8-byte), but I'm only speculating.
Bill the Lizard
@Bill: even if MSIL only supports module-2**32 arithmetic, the C# compiler would still be free to insert a narrowing conversion when necessitated by storage of the result into a variable as narrow as the operands.
Ben Voigt
@Ben Voigt: I instinctively never want the compiler to insert a narrowing cast for me. However, I suppose in this case you are implicitly telling it to do the cast by assigning the result to a byte. I can't find any fault in your logic.
Bill the Lizard
Ben Voigt
+2  A: 

For addition, multiplication, and subtraction, there's a fairly good explanation: Including the carry bits in the calculation and then throwing them away is far easier than figuring out the carry bits if they were thrown away originally.

For bitwise operators (intersection, inclusive union, exclusive union, complement) that reasoning simply doesn't hold water. The only thing I can think of is that sign-extension would be somewhat ambiguous if you started with a mixture of signed and unsigned operands and then saved the result in a wider type. But that doesn't explain why bitwise operations which are unary or where all operands have the same type should widen the result to int. I consider it a very annoying design flaw with C# that:

byte a, b;
byte c = a | b;

generates an error.

Ben Voigt
I agree with your overall point, but isn't this an "annoying design flaw" in C# rather than .NET? F# defines logical and arithmetic operations on bytes which return bytes, for instance.
kvb
@kvb: You're right, fixed. Thanks.
Ben Voigt
+4  A: 

Raymond Chen answers your question here:

http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx

Eric Lippert
Raymond didn't address bitwise operations, and got called on that in the comments. Would you like to comment on why NOT/AND/OR/XOR cause promotion?
Ben Voigt