tags:

views:

221

answers:

4

There doesn't seem to be a way to use C#'s ternary operator on two bytes like so:

byte someByte = someBoolean ? 0 : 1;

That code currently fails to compile with "Cannot convert source type 'int' to target type 'byte'", because the compiler treats the numbers as integers. Apparently there is no designated suffix to indicate that 0 and 1 ares bytes, so the only workarounds are to a) cast the result into a byte or to use an if-else control after all.

Any thoughts?

+15  A: 
byte someByte = someBoolean ? (byte)0 : (byte)1;

The cast is not a problem here, in fact, the IL code should not have a cast at all.

Edit: The IL generated looks like this:

L_0010: ldloc.0          // load the boolean variable to be checked on the stack
L_0011: brtrue.s L_0016  // branch if true to offset 16
L_0013: ldc.i4.1         // when false: load a constant 1
L_0014: br.s L_0017      // goto offset 17
L_0016: ldc.i4.0         // when true: load a constant 0
L_0017: stloc.1          // store the result in the byte variable
Lucero
This was acknowledged by the asker. He's looking for alternatives
Randolpho
@Randolpho: No, the OP said he could cast the *result* - Lucero's answer casts the *operands* which will have a different effect; the cast is effectively done at compile-time rather than execution time.
Jon Skeet
Ahh.... good point.
Randolpho
@Jon, thanks. I just tried this an the IL shows no cast (which was to be expected, since the IL stack anyways only uses 32-bit values and then stores it into a byte, effectively truncating it).
Lucero
+3  A: 

That compiles OK on VS2008.

Correction: This compiles OK in VS2008:

byte someByte = true ? 0 : 1;
byte someByte = false ? 0 : 1;

But this does not:

bool someBool = true;
byte someByte = someBool ? 0 : 1;

Odd!

Edit: Following Eric's advice (see his comment below), I tried this:

const bool someBool = true;
byte someByte = someBool ? 0 : 1;

And it compiles perfectly. Not that I distrust Eric; I just wanted to include this here for the sake of completeness.

CesarGon
yeah, same trip up here... maybe it's the fact that your first statement is guaranteed to always hit 0?
kolosy
We need Skeet. :p
CesarGon
@CesarGon: have you tried it this way [byte someByte = (somebool == true) ? 0 : 1; ] I had to use square brackets to indicate the code block!
tommieb75
@tommieb75: doesn't compile. Says can't convert int to byte.
CesarGon
That's because the compiler knows at compile-time that it evaluates to "byte someByte = 0;" which is fine.
Edward Robertson
@CesarGon: funny!!! You would think it would! Wouldn't ya! :) Unless you put an explicit cast (like Lucero's answer above) or use a hex notation? Speaking of funny syntaxes, one particular syntax as you type it in VS 2008 causes it to crash (intellisense feature that goes awol!)
tommieb75
@Edward: but 0 is of type int, not byte. So it should give you the same compile error.
CesarGon
Seems like a (minor) bug, probably caused by the compiler shortcutting the condition (see also constant folding: http://en.wikipedia.org/wiki/Constant_folding ) because it does know the outcome, therefore the operator is completely ignored.
Lucero
Yay!! Found my first bug in the C# compiler!!
CesarGon
@CesarGon: check this out... http://www.codeproject.com/Messages/3298609/OK-now-I-am-doomed-modified.aspx - in summary : Step 1: Create C# console project.Step 2: In Main method type: var x = __arglist(args);Step 3: Ummm....does VS2008 crash at this point!
tommieb75
@tommieb75: It does crash, indeed.
CesarGon
Sorry to burst your bubble but the conditional operator behaviour is not a bug. First see section 7.18. Since all the operands are compile-time constants of integral or boolean type, the conditional operator is evaluated at compile time. It evaluates to a constant expression of value 1 (or 0), and the type of the constant expression is int. Now look at section 6.1.8: "a constant expression of type int can be converted to byte provided the value is within the range of byte". So there you go; this is correct and according to spec.
Eric Lippert
@Eric: Awww. Well, many thanks for the clarification. I have edited my answer to show an example of what you just said.
CesarGon
@tommieb75: you can use backticks to indicate code
RCIX
@Eric: since I suppose that you're referring to my comment... it still seems strange that the behavior is different. That's because the compiler could just as well know that only 0 or 1 are going to be the result of the runtime computation, and both of these constants fall under the section 6.1.8 rule. So if the case where the code works at compile time is correct, isn't the case where the compiler doesn't accept the runtime-evaluation with the *known* outcome of 0 or 1 wrong then?
Lucero
Sure, in theory that's possible. But consider for a moment what you would have to do to write a compiler that had that feature. Suppose you had (A ? (B ? 0 : 1) : (C ? 2 : (D ? 5 : 265))). Should the compiler have to track "the result of this expression is 0, 1, 2, 5 or 265 and therefore this is not convertible byte but is to ubyte, or ushort, or short, or int"? It is certainly possible to write all the bookkeeping code that keeps track of when a conditional expression could be one of several constants, but we have other higher priorities than that feature.
Eric Lippert
+3  A: 
byte someByte = (byte)(someBoolean ? 0 : 1);
Matt Davis
+6  A: 

You could always do:

var myByte = Convert.ToByte(myBool);

This will yield myByte == 0 for false and myByte == 1 for true.

Randolpho
I'm actually surprised that it took this long for someone to suggest it.
R. Bemrose
Too busy making silly comments, I guess. :)
Randolpho