4

Why the following code returns false?

public static void Main()
{
    bool? someCondition = true;
    bool someConditionOverride = false;


    bool? result = someCondition ?? someConditionOverride ? false : (bool?)null;

    Console.WriteLine(result);
}

I was exprecting the result will be true, since someCondition is not null and ?? operator will return true. However looks like right operand is calculated first and the left part is simply ignored.

Adding brackets fix the confusion:

bool? result = someCondition ?? (someConditionOverride ? false : (bool?)null)

And the result will be true. However I am still curious why left part had been ignored in the first example.

Artem
  • 2,084
  • 2
  • 21
  • 29
  • [What is the operator precedence of C# null-coalescing (??) operator ?](https://stackoverflow.com/questions/511093/what-is-the-operator-precedence-of-c-sharp-null-coalescing-operator) explains it... probably can be used as duplicate. – Alexei Levenkov Jun 07 '17 at 15:56
  • This actually a really good question –  Jun 07 '17 at 16:05
  • Simply reading the expression I'd expect `??` to be evaluated first, thus causing `false` to be returned. I wouldn't expect `?:` to have higher precedence just like I wouldn't expect `+` to have precedence over `-` – Panagiotis Kanavos Jun 07 '17 at 16:09
  • I'm interested to know what the semantics of your condition variables actually are; this is an unusual conditional expression and I don't have any intuition about what the real problem this solves looks like. – Eric Lippert Jun 07 '17 at 17:10

1 Answers1

17

"the left part is simply ignored"? How likely do you really think that is?

Operator precedence dictates that your first version is parsed like so:

bool? result = (someCondition ?? someConditionOverride) 
                   ? false 
                   : (bool?)null;

someCondition isn't null, and it is true. Therefore, this expression evaluates as true:

(someCondition ?? someConditionOverride) 

So we get the ? branch, and the whole expression returns false, just like you told it to.

Adding the brackets that you added completely changes the meaning of the expression. It fixes your confusion, in a limited sense, by bringing the actual meaning of the expression in line with your original intent; but the compiler is never confused. In C#, compiler confuses you.

To reduce my own confusion, I never rely on operator precedence. I parenthesize everything. If I had designed the language, the grammar would require it (unless Eric comes by and tells me why that's actually not such a good idea after all, for some reason that will make perfect sense to me once Eric explains it).

UPDATE: Prediction validated: Eric came by and said that too many people would find it ridiculous to have to parenthesize a + b * c, and if you allow that, there's no reasonable way to define the exceptions. Well, if they won't tolerate being forced to parenthesize everything, they won't, however much I think they should.

  • 4
    "In C#, compiler confuses you" - +1 for that alone! – Matt Hogan-Jones Jun 07 '17 at 15:58
  • 2
    I'd vote for "I parenthesize everything. If I had designed the language, the grammar would require it." That's the essense of the story – Artem Jun 07 '17 at 16:06
  • @Artem why would `?:` have higher precedence over `??` ? I'd expect the operators to be evaluated left-to-right – Panagiotis Kanavos Jun 07 '17 at 16:11
  • @itsme86 because that's the default in math as well. When all operators have the same precedence, evaluation is left to right. Conditionals have the lowest precedence – Panagiotis Kanavos Jun 07 '17 at 16:18
  • 5
    It's a tricky design problem. I think that most people would agree that requiring parenthesis of `a + b * c` is too heavy a burden. If we are going to have precedence (and associativity) rules then the question is, what are they? This is hard particularly for the operators that we have not all been trained up on since we are children. One would be forgiven for not knowing whether `a ?? b + c ?? d` is `(a??b) + (c??d)` or `a??(b+c)??d`; our intuitions do not lead us one way or the other. (It is the latter.) – Eric Lippert Jun 07 '17 at 17:00
  • 1
    As for the question of why `??` is higher precedence than `?:` -- I do not know why. There are arguments to be made for higher, lower and equal precedence, and the details of the arguments that were made in 2004 in the C# design team meeting, and why some of those arguments prevailed over others, are lost to the mists of time. I don't know of any compelling reason to choose one over the other. – Eric Lippert Jun 07 '17 at 17:03
  • 3
    @EricLippert Thanks. Honestly, I do literally parenthesize `a + (b * c)`, and I don't personally find it a burden. It's like putting braces on a one-line if, in my view. I guess I'm not likely to convince anybody, though. – 15ee8f99-57ff-4f92-890c-b56153 Jun 07 '17 at 17:15
  • @PeterCooperJr. I can parenthesize everything right now, and not have to forage in the woods to feed myself. I love the fact that LISP exists, and folks smarter than me clearly find enormous value in it, but I don't personally find it congenial. – 15ee8f99-57ff-4f92-890c-b56153 Jun 07 '17 at 18:55
  • 2
    @EdPlunkett: The question is not "should we prohibit Ed from doing this if he enjoys that sort of thing?" Plainly not! You be you. Rather "should we require everyone to have Ed's easygoing attitude towards excessive parenthesization?" I think there would be much bike shedding over that one. That said, there are languages that require parenthesization when precedence or associativity is hard to understand, and I think there's some value in that. – Eric Lippert Jun 07 '17 at 21:55