10

I know that doing (myValue ?? new SomeClass()) is similar to (myValue == null ? new SomeClass() : myValue)

But out of curiosity, is there any performance benefit when I call a function, say (getResult() ?? new SomeClass()). Will getResult() get executed twice? It seems unintuitive since I've specified the method call only once.

arviman
  • 5,087
  • 41
  • 48
  • http://stackoverflow.com/questions/6208067/operators-instead-of-ifelse – Mukund Apr 10 '15 at 06:35
  • http://stackoverflow.com/questions/3431064/what-is-operator-in-c – Mukund Apr 10 '15 at 06:35
  • above two are great answer, explaining ?? . Please have a look. – Mukund Apr 10 '15 at 06:36
  • 1
    @Mukund - both explain what a coalescing operator does, but do not answer the question of whether the expression is evaluated once\twice. (hamid's answer in the second one seems to indicate twice but I don't believe it is correct simply because he was just trying to explain what it does, not what is generated in the IL).. It will be easy enough to test using a static counter, but I'd rather hear it from an expert ;-) – arviman Apr 10 '15 at 06:45
  • The premise of this question is incorrect. The null coalescing operator does not expand to a conditional expression. – phoog May 29 '15 at 23:02
  • @phoog - I'm aware of that. By "expands" I meant "is equivalent to". Fixed it though, thanks! – arviman Jun 01 '15 at 08:28
  • @arviman but that's just it. It is *not* equivalent, precisely because it does not evaluate the first expression more than once. – phoog Jun 01 '15 at 16:48
  • @phoog - you're confusing functional equivalency with implementation details. We're referring only to semantics...the "what", not "how". – arviman Jun 03 '15 at 10:47
  • @arviman As far as I see it, you are the one confusing functional equivalency with implementation details. `A ?? B` is not functionally equivalent to `A == null ? B : A` precisely because they are different in terms of side effects. `A ?? B` is functionally equivalent to `var temp = A; temp == null ? B : A`. – phoog Jun 03 '15 at 17:33
  • @phoog I get your point. But, how else was I supposed to communicate the similarity between null coalescing and conditional when I was not aware of the background implementation. (just a rhetorical question) – arviman Jun 10 '15 at 06:41
  • 1
    @arviman point taken. I just read your question as "I know X is true, so is X false?" where X is false, so the opening sentence of the question is a contrafactual assumption. I realize your question is rhetorical but I'll answer it anyway: I would probably just have asked "is the left operand of the `??` operator executed twice when its result is non-null" although somewhat more verbosely. But that's after this whole discussion. Phrasing a question from scratch can be difficult, I agree. – phoog Jun 10 '15 at 21:09

1 Answers1

16

Well, if by "caching" you mean storing it in a temporary variable, then yes.

This construct:

var result = (getResult() ?? new SomeClass());

can be thought of to be equivalent to this:

var <temp> = getResult();
if (<temp> == null)
    <temp> = new SomeClass();
result = <temp>;

This also tells you that the second part, the operand after ?? isn't executed at all if the first operand is not null.

So to answer your concrete questions:

  1. Each operand is evaluated at most once
  2. The second operand is only evaluated if the first one evaluates to null

Note also that you can chain these:

var result = first() ?? second() ?? third() ?? fourth();

Which results in:

  1. Evaluates first()
  2. If first() evaluated to null, evaluates second()
  3. If second() evaluated to null as well, evaluates third()
  4. If all of the above evaluated to null, finally evaluates fourth

The result is the first (no pun intended) non-null value returned.


This type of code is about to get even better in new C# with the new ?. operator:

var result = first?.second?.third;

This is basic . handling, ie. it will read the second member of first, and then the third member of whatever second is, but it will stop at the first null, and will also make sure to evaluate each step only once:

(obj as IDisposable)?.Dispose();

obj as IDisposable will only evaluate once.

TryGetObjectToSave()?.Save();

Will only call TryGetObjectToSave() once, and if it returns something, the Save() method on that something will be called.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825