Update: It seems that I am not being clear enough of what exactly I am asking (and as the question developed over time I also lost track a bit), so here is a tl;dr version:
var test1 = a is byte & b; // compiles
var test2 = a is byte? & b; // does not compile
var test3 = a is byte? && b; // compiles
This means - as I understand - that the ?
type modifier has lower precedence (as it's not an operator this might not be the best word) than the &
operator, but higher than the &&
operator. Is it so? Where is this described in the standard?
And the original question:
While trying to figure out the answer to the second puzzle from Jon Skeet's excellent blogpost, A Tale of two puzzles, I faced a problem:
unsafe private void Test<T>(T a, bool b)
{
var test1 = a is byte? & b; // does not compile
var test2 = a is byte? && b; // compiles
var test3 = a is byte ? & b : & b; // compiles
}
Here I am using an unsafe
context as my actual goal requires it (e.g.: the third line), but it is not necessary for reproducing the issue I raise. (However it might have an effect, as it introduces the address-of operator as an alternative for the &
symbol.)
The first line does not compile (the others do), it gives the following error message:
Syntax error, ':' expected
This means that in that case the compiler sees the line as
var test1 = (a is byte) ? &b [: missing part that it complains about];
While in the second line it sees it as:
var test2 = (a is byte?) && (b);
I checked operator precedence (here), and the order (from highest to lowest) is the following: &, &&, ?:
, so this alone does not explain why the first line does not compile while the second does (Or at least not for me - maybe this is where I am wrong...) Edit: I understand why the second compiles, so please don't concentrate on this in your answers.
My next hunch was that somehow the precedence (if there is such thing) for the ?
type modifier is somewhere between those two (or in fact three) operators (&
and &&
). Can it be so? If not could someone please explain the exact behavior that I am experiencing? Is the evaluating order of ?
type modifier clearly described somewhere in the standard?
Edit: I am also aware that there is an unary address-of operator (actually that's the trick I am trying to use for the solution...), which plays a role here, but my question still stays the same.
In the same unsafe
context those happily compile:
var test1 = true & b;
var test2 = true && b;
// or
var test1 = a is byte & b;
var test2 = a is byte && b;
So I think it must be related to the ?
modifier/operator, and not solely to the address-of operator taking precedence (otherwise the two test1
lines would not compile).
P.S.: I know that I can add parentheses to my code, so it will compile, but I want to avoid that:
var test = (a is byte?) & b; // compiles
Update: I experimented with Roslyn a little, and I thought it might be a good idea to attach the ASTs for the various statements:
var test1 = a is byte & b;
var test2 = a is byte? & b;
var test3 = a is byte? && b;
I want to emphasise that I am not looking for a solution for the original problem in the linked article (of course I am looking for one, but I ask you not to give an answer here please, as I would like to find that out on my own.) Also, please don't comment if I am on a completely wrong track in finding the solution, I only mentioned the puzzle to give some context for my specific problem, and to provide a good-enough excuse for writing code like this.
The clue here is the unsafe
keyword. There are actually two different & operators - bitwise-AND & operator you're used to, but also the address-of & operator, which not only has higher precedence, but is evaluated right-to-left, like all unary operators.
This means that &b
is evaluated first, and results in a pointer value. The rest of the statement is, as the compiler complains, unparseable. It's either (a is byte?) (address)
, or (as the compiler tries to parse it) (a is byte) ? (address)
and is missing the :
.
I get the same compile error when replacing & with +
or -
, both symbols that can be either unary or binary operators.
The reason the second statement compiles fine is that there isn't a unary, right-to-left high-precedence && operator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With