22

I've just tried the following, the idea being to concatenate the two strings, substituting an empty string for nulls.

string a="Hello";
string b=" World";

-- Debug (amusing that ? is print, doesn't exactly help readability...)

 ? a ?? "" + b ?? "" 

-> "Hello"

Correct is:

? (a??"")+(b??"")
"Hello World"

I was kind of expecting "Hello World", or just "World" if a is null. Obviously this is todo with operator precedence and can be overcome by brackets, is there anywhere that documents the order of precedence for this new operator.

(Realising that I should probably be using stringbuilder or String.Concat)

Thanks.

Abel
  • 56,041
  • 24
  • 146
  • 247
AndyM
  • 3,574
  • 6
  • 39
  • 45

4 Answers4

40

Aside from what you'd like the precedence to be, what it is according to ECMA, what it is according to the MS spec and what csc actually does, I have one bit of advice:

Don't do this.

I think it's much clearer to write:

string c = (a ?? "") + (b ?? "");

Alternatively, given that null in string concatenation ends up just being an empty string anyway, just write:

string c = a + b;

EDIT: Regarding the documented precedence, in both the C# 3.0 spec (Word document) and ECMA-334, addition binds tighter than ??, which binds tighter than assignment. The MSDN link given in another answer is just wrong and bizarre, IMO. There's a change shown on the page made in July 2008 which moved the conditional operator - but apparently incorrectly!

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I didn't realize the point about nulls in string concatenation. Nice. – EnocNRoll - AnandaGopal Pardue Feb 04 '09 at 13:01
  • 8
    It's interesting that: string s= null assigns s to null whereas string s=null+null assigns s to "" – AndyM Feb 06 '09 at 09:18
  • 2
    for "Don't do this", +1 is not enough. – Simon Oct 14 '09 at 09:52
  • 3
    It's funny to try something like this: int? a = 4; int? b = 5; int result = a ?? 0 + b ?? 0; what's the result? 9? nah! it's 4! when a is not null the result is just a. If you want to get 9 you have to do: int result = (a ?? 0) + (b ?? 0); So, always use parenthesis in these cases. – Francisco Goldenstein Jan 12 '18 at 14:14
  • @FranciscoGoldenstein even better: something like SomeMethod(a ?? 0 + b ?? 0) would *still* use 4 as the value for the input parameter of the called method (which makes totally sense given what's written above, but would probably confuse you even more if you didn't know) – SPArcheon Apr 19 '19 at 10:42
6

Never rely on operator precedence. Always explicitly specify how you want your code to act. Do yourself and others a favour for when you come back to your code.

(a ?? "") + (b ?? "")

This leaves no room for ambiguity. Ambiguity is the breeding ground of bugs.

Garry Shutler
  • 32,260
  • 12
  • 84
  • 119
  • 10
    Define "when it matters" - would you use it for a + b * c as well? Even if you regard that as too ambiguous, I suspect there are examples I could find where it matters but *everyone* considers it obvious. I agree with the general idea, but not quite how far you'd go :) – Jon Skeet Feb 04 '09 at 13:00
  • 2
    I would probably use it in your example as well. I'd much rather it be explicitly set out for me than have to think, even for a second. That second of thought gives opportunity for error. – Garry Shutler Feb 04 '09 at 13:24
  • Having realised how extreme I stand on it, I've removed the "when it matters". Though I wouldn't bracket up x + y + z, I feel making the extreme statement makes my point clearer. – Garry Shutler Feb 04 '09 at 13:26
  • I'll try to come up with an example which is so obvious that I suspect you wouldn't bracket it :) – Jon Skeet Feb 04 '09 at 13:49
  • Hehe. I'm sure you'll think of one but making an extreme stand makes for a better answer in my opinion. – Garry Shutler Feb 04 '09 at 13:54
  • 2
    Okay, here's a sort of example - do you always bracket for associativity as well as precedence? One of the nice things about ?? is that you can write "a ?? b ?? c ?? d". Given that that's a fairly idiomatic use, I think it's clearer than a ?? (b ?? (c ?? d)). But admittedly that's not precedence :) – Jon Skeet Feb 04 '09 at 17:39
  • 1
    In that case I would write it as you would. I would however avoid having to write code that did that at all costs! ;) – Garry Shutler Feb 04 '09 at 23:46
5

The operator precedence is documented on MSDN.

However the precedence on MSDN contradicts the precedence in both the downloadable C# spec also from Microsoft, and the spec on ECMA. Which is a little odd.

Irrespective, as Jon Skeet said in his response, best not to rely on precedence of operators, but to be explicit through use of brackets.

TrueWill
  • 25,132
  • 10
  • 101
  • 150
Sam Meldrum
  • 13,835
  • 6
  • 33
  • 40
  • 1
    Cheers. Searching for ?? in google was obviously not the way. Quite annoying that it's so low. – AndyM Feb 04 '09 at 12:21
  • I think this must be wrong - see ECMA reference, and consider: string a = null; string b = a ?? "foo"; What is b? – Douglas Leeder Feb 04 '09 at 12:28
  • 1
    That MSDN page is definitely wrong - it contradicts Microsoft's own spec. – Jon Skeet Feb 04 '09 at 13:05
  • 1
    Leaving answer up as it is the MSDN link which *should* give the right answer. Hopefully Microsoft will fix that. If anyone thinks I should delete, please le me know in comments. Thanks. – Sam Meldrum Feb 04 '09 at 13:30
  • 1
    I don't think you should delete it, but I suggest you edit the answer to explain that that MSDN page doesn't reflect the contents of the downloadable C# spec. – Jon Skeet Feb 04 '09 at 13:54
  • I think MSDN is correct now, can someone confirm? (I just come over here and want to make sure I understand correctly) – apple apple Feb 25 '20 at 14:43
2

It interesting that http://msdn.microsoft.com/en-us/library/6a71f45d.aspx and http://en.csharp-online.net/ECMA-334:_14.2.1_Operator_precedence_and_associativity give different precedence to ??.

msdn:

  1. Conditional
  2. Assignment
  3. Null-coalescing
  4. Lambda

ECMA:

  1. Null Coalescing
  2. Conditional
  3. Assignment

I think the msdn must be wrong, consider:

string a = null;
string b = a ?? "foo";
// What is b now?
Douglas Leeder
  • 52,368
  • 9
  • 94
  • 137