Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"?" type modifer precedence vs logical and operator (&) vs address-of operator (&)

Tags:

operators

c#

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;

AST for test1 line

var test2 = a is byte? & b;

AST for test2 line

var test3 = a is byte? && b;

AST for test3 line


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.

like image 958
qqbenq Avatar asked Jun 19 '14 11:06

qqbenq


1 Answers

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.

like image 128
Avner Shahar-Kashtan Avatar answered Oct 05 '22 00:10

Avner Shahar-Kashtan