0

Note to future visitors: This question was based on faulty repro code. The ?. operator does indeed short circuit. You can close this browser tab now.


There are many sources on the web that claim that the null conditional operator (?.) short circuits (e.g. http://www.informit.com/articles/article.aspx?p=2421572, search for "circuit"). I cannot detect any such thing:

    static void Main()
    {
        var c = new C();

        Console.WriteLine(c?.Inner?.Inner); //does not rely on short circuiting, works
        Console.WriteLine(c?.Inner.Inner); //throws NullReferenceException
    }

    class C
    {
        public C Inner;
    }

Here, the first line works because of the second ?.. The second ?. saw null as its first operand and therefore returned null as well. This is not short circuiting.

Apparently, the rest of the chain executes even if the null case was triggered. The chain is not aborted. To me, short circuiting means that the chain is aborted. MSDN claims this is the case but the code example does not demonstrate short circuiting:

//The last example demonstrates that the null-condition operators are short-circuiting
int? count = customers?[0]?.Orders?.Count();
// null if customers, the first customer, or Orders is null

Was this behavior ever changed during the C# 6 development cycle? That would explain the bad sources on the web. And why is there so much talk about short circuiting if it's not there? I might be misunderstanding something here.

This is not a duplicate because it's about whether the operator short circuits or not (answer: no, although the accepted answer does not say that). This candidate is about nullable booleans and otherwise unrelated.

Community
  • 1
  • 1
boot4life
  • 4,966
  • 7
  • 25
  • 47
  • I would suggest you to read again the article you are referring to. – Ivan Stoev Jun 24 '16 at 16:43
  • @IvanStoev anything more concrete? I'm not sure what I'm supposed to do with that comment. Clearly, I'm misunderstanding something but this does not clear it up for me. – boot4life Jun 24 '16 at 16:48
  • This is from the link: "*The null conditional operator short-circuits, which means that you can chain multiple ?. operators, knowing that the first null encountered prevents the remaining (rightmost) components of the expression from being evaluated.*" Note the **chain multiple**. – Ivan Stoev Jun 24 '16 at 16:54
  • @IvanStoev I understand the claim. I disagreed with it because my experiment was wrong which I now know. This is not a problem with me misunderstanding the article. – boot4life Jun 24 '16 at 16:56
  • Actually the line with comment `//does not rely on short circuiting, works` does rely on short circuiting. – Ivan Stoev Jun 24 '16 at 16:58
  • I disagree with that position. I have explained in the comments below why. Not sure why it would be called SC if all instances of ?. are necessary. Also, that code does not demonstrate my (false) point anyway because I should have added one more `.Inner`. This *does* demonstrate SC: `c.Inner?.Inner.Inner`. – boot4life Jun 24 '16 at 17:01

3 Answers3

7

It does short-circuit (if by that we mean "terminate the chain of calls).

Consider this code:

using System;

namespace ConsoleApplication1
{
    class C
    {
        public C Inner
        {
            get
            {
                Console.WriteLine("Inner called.");
                return this; // Change this to `return null;`
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var c = new C();

            var x = c?.Inner?.Inner?.Inner;
        }
    }
}

Run that and it will print

Inner called.
Inner called.
Inner called.

Now change return this; to return null;, and it will print

Inner called.

thus demonstrating that the call chain was stopped at the first null.

Now change the expression to:

var x = c?.Inner?.Inner.Inner;

and it will still print

Inner called.

because it is being short circuited.

Obviously it has to access Inner at least once to see if it is null. If c itself is null, then Inner isn't accessed at all.

Note that given the expression:

var x = c?.Inner.Inner;

it will give a null reference exception at the first use of .Inner because it has already checked that c is not null using c? and now it goes on to use .Inner.

If c was null, it would not have proceeded to access .Inner at all because of the c?..

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • See my comment at the other answer. It does not short circuit. All instances of `?.` are needed here to avoid a crash. If we indeed observed SC then only the first `?.` would be required. – boot4life Jun 24 '16 at 16:36
  • In other words: How would you devise a test to see if there is SC or not? How do you define SC? I define it as the rest of the chain being cancelled by *one* `?.` operator. – boot4life Jun 24 '16 at 16:37
  • @boot4life it always is cancelled by a single `?.`. It just may be a different `?.` each time depending on what is `null`. – i3arnon Jun 24 '16 at 16:38
  • Then let's talk about the exact case from my question. If the first `?.` SC's as you claim, why is the second one needed? – boot4life Jun 24 '16 at 16:40
  • 3
    @boot4life Because the first operates on a thing that is **not** `null`, and the second on a thing that **is** `null`. – i3arnon Jun 24 '16 at 16:41
  • Ahh that's bad. My code is not showing what I want to show. Will investigate now. – boot4life Jun 24 '16 at 16:42
  • 2
    @boot4life The `c?.` checks the value of `c` - it doesn't check the value of `Inner`. Only `Inner?.` will check the value of `Inner`. It's quite straightforward really - the `?.` checks the thing to the left of it, and if it is null it stops and returns null. – Matthew Watson Jun 24 '16 at 16:43
  • I understand what the two of you are claiming. I can reproduce it in my toy example. The thing is in the real code, which is not suitable to post because it is huge, I think I'm seeing not SCing behavior. Clearly, I'm wrong on that but this is what lead to this question (in addition my repro was wrong which I did not notice. This mislead me by falsely confirming my false belief). – boot4life Jun 24 '16 at 16:50
  • Maybe the C# compiler is doing something weird. Reflector crashes when decompiling the method. – boot4life Jun 24 '16 at 16:52
  • I will continue to investigate what I'm seeing. The question is finally answered due to my misunderstanding having come to light. Thank you. – boot4life Jun 24 '16 at 16:59
3

Short circuit here means that when you have for example obj?.Property1?.Property2?.Property3 and obj is null then the whole expression returns null and no other properties are called (as they will throw).

That short circuiting can happen on each ?. depending on which part is null. if obj isn't null and the first Property is then only the other 2 won't be called. Same for the second and so forth.

The thing being short circuited is the expression, not the rest of the statements after that expression.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
0

In real simple terms, short-circuiting is a guarantee that if it determines that one property is null, it's not going to keep trying to evaluate the rest.

It might be clearer with an example that doesn't involve the null operator.

In the example below, we're checking to see if x is null before checking the value of its property.

if(x != null & x.SomeProperty == 1)

But this is still going to throw an exception if x is null because it's going to evaluate both conditions. Even if x is null it's still going to try to check x.SomeProperty and it's going to throw a NullReferenceException.

But if we use the && operator instead

if(x != null && x.SomeProperty == 1)

Then it "short circuits." If the first condition isn't true then it won't even evaluate the second condition. It's checking to see if they are both true. But if the first one isn't true then there's no way they can both be true - the value of the second one doesn't matter. So it stops after the first condition.

Short circuiting eventually means that if it evaluates anything that renders the remaining conditions irrelevant then it is guaranteed not to evaluate the remaining conditions.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
  • I understand what SC is (and I described what it is in the question). I thought the code in the question demonstrates that it's not there. But the code was wrong and it's there. – boot4life Jun 25 '16 at 12:52