Click here to Skip to main content
Click here to Skip to main content

The Null Coalescing Operator (??)

By , 28 Sep 2007
 

Introduction

I'm constantly surprised by the number of developers who aren't aware of this handy piece of syntax. It's my favourite thing to come out of C# 2.0 and no developer should be without it.

Like the conditional (?:) operator's big brother... introducing it for your coding pleasure...

The Null Coalescing Operator (??)

The null-coalescing-operator is a brilliant new terse operator that provides syntax for beautifully concise if statements. Essentially, it returns the left-hand-side of the ?? operator, unless null, in which case it executes and returns the right-hand-side of the operator. This may be a statement or a variable reference. Let's jump straight to some examples:

// used inline outputs the value foo or if null returns Undefined
Console.WriteLine("The value of foo is " + (foo ?? "Undefined") + ".");
    
Input:  foo = "24";
Output: The value of foo is 24.
    
Input:  foo = null;
Output: The value of foo is Undefined.

The operator is right-associative meaning statements can be chained together; thus returning the first non-null instance:

// assigns foo to the first non-null instance, else returns Undefined
string foo = foo1 ?? foo2 ?? foo3 ?? foo4 ?? "Undefined";
    
Console.WriteLine("The value of foo is " + foo + ".");

Input:  foo1 = null;
        foo2 = null;
        foo3 = null;
        foo4 = null;
Output: The value of foo is Undefined.
    
Input:  foo1 = null;
        foo2 = "foo2";
        foo3 = null;
        foo4 = "foo4";
Output: The value of foo is foo2.

Handling null ViewState references:

// try to assign ViewState value as an int, else if null assign 123
int foo = (int?)ViewState["foo"] ?? 123;
    
Response.Write("The value of foo is " + foo + ".");
    
Input:  ViewState["foo"]=1;
Output:  The value of foo is 1.  
    
Input:  ViewState["foo"]=null;
Output:  The value of foo is 123.  

And my personal favorite, on demand field instantiation:

private IList<string> foo;

public IList<string> Foo
{
    get
    {
        return foo ?? (foo = new List<string>());
    }
}

Here's an interesting example derived from an idea in the discussions below. It shows how an operator override can be used within an object's definition to enable shorthand syntax for double-null checking. The scenario is checking an object property for null using a null-coalescing-operator, but also defaulting when null-object-reference occurs; which would normally cause a runtime exception. (Note that I don't recommend actually using this approach, I just thought it made an interesting example.)

public class Address
{
    private static Address Empty = new Address();
    public string StreetName = null;
    
    public static Address operator +(Address address)
    {
        return address ?? Empty
    }
}
  
Console.WriteLine("The street name is "+ (+address).StreetName ?? "n/a" + ".");
  
Input:  address = new Address();
Output:  The street name is n/a.  
    
Input:  address = new Address();
            address.StreetName = "Regent St";
Output:  The street name is Regent St.    
    
Input:  address = null;
Output:  The street name is n/a.

The Rules

To use the null-coalescing-operator, there are some compile-time ground rules.

  • The left-hand-side must evaluate to a reference or nullable type.
  • All evaluated statements must be of matching type, unless they can be implicitly converted.

Summary

As you can see from the examples above, this little gem is very powerful and the possibilities are endless. Of course the benefits are purely syntactical, but it helps keep the code clean and easier to follow. I hope you enjoy it as much as I do.

History

  • 28th September, 2007: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

TheCodeKing
Architect
United Kingdom United Kingdom
Member
Mike Carlisle - Technical Architect with over 10 years experience in a wide range of technologies.
 
@TheCodeKing

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralAn alternate viewmemberBig Al 071 Oct '07 - 6:38 
Whilst I respect your opinion, I would like to put forward an alternate point of view. I’m expecting a barrage of abuse here… but someone has to question it …
 
Why is a “new terse operator that provides syntax for beautifully concise if statements.” a good thing? I’ve coded in assembler for about half a dozen different processors and probably twice that many languages, and this is the sort of thing I would like to get away from, especially when inheriting someone else’s code. The purpose of a compiled language is (amongst other things) to increase legibility, maintainability; reduce errors and provide a greater degree of abstraction from the real processor. Not to make things more “terse”. If I want terse, then I’ll go back to assembler. I am quite prepared to go terse to get performance, but don't want it in a high level language.
 
I could come up with a language that uses "#Variable{…}" which means repeat until variable is 0… or other symbol combinations to remove the need for other language elements like if, while, for and foreach. Would these all be good things?
 
If this line of reasoning is followed to its conclusion, then code will more resemble hieroglyphics which needs decoding than something understandable by simply reading it.
 
I know this is a trivial case, but it is the view of it being taken as read as a good thing that bothers me. I would quite happily type 6 or 7 more characters to make things more readable for others (or myself) later, and many environments these days help cut down typing time finger strain if that's the worry.

GeneralRe: An alternate viewmemberTheCodeKing1 Oct '07 - 8:18 
Interesting, never heard anyone argue against the use of terse operators.
 
Surely they require less lines of code and therefore less prone to bugs, are much easier to read and understand, and produce more consistent reliable output due to the way it's compiled.
 
My opinion is that there's a happy medium between code being incomprehensible due to being too low level (such as assembly), and code being incomprehensible due to being overly bloated.
 
I agree they shouldn't be thrown in without due care and attention, otherwise again code just becomes incomprehensible (look at perl). As it stands I find C# a clean language, and welcome a hand-full of terse operators to simply common code blocks. Personally I don't want to be writting assembly any more than I want to be writting null cheecking if statements.
 
Luckily the good old 'if' is always there if you prefer going 'old school'.
 

 

GeneralRe: An alternate viewmemberHal Angseesing1 Oct '07 - 9:06 
Funnily enough I have worked in a number of shops (C++ rather than C#) where the tertiary operator was disallowed as it was hard to read. Of course this is all "in the opinion of the writers of the standards" but it was based on bugs generated, debugging effort and especially people relatively new to C++. For similar reasons the "clever" constructs that you can do with pointer dereferencing and incrementing were not allowed.
GeneralRe: An alternate viewmemberBig Al 071 Oct '07 - 14:47 
Hi CodeKing
Ended up … long winded… sorry!
 
I agree less lines of code leads to less bugs... but that is a volume thing... i.e. zero lines means no bugs, thousands of lines means many bugs! Many things drive quantity of bugs ranging from requirements analysis, software architecture all the way down to quality of written lines of code. And yes, even the compiler and sometimes even processor microcode!
 
The following lines of code are reasonably concise – but probably load of B***cks, because I've not spent any time on it, but does serve to illustrate how I feel about it. I claim no correctness here, just an illustration…
 
WheelsDown = TrySenseGearDown();
etc
WarningLightOn = !WheelsDown ?? true && (RadarAltitude - RadarAccuracy ?? LastRadarAltitude – RadarAccuracy-200 ?? PressureAltEstimate - PressureAccuracy ?? 0) < 500;
 
Personally I would just feel a bit more comfortable to fly in something if this was coded in a bit more long hand and spelt out. Why do I feel this way – I think a competent coder writing it longhand (spelt out) is less likely to have bugs, and more importantly someone coming along later (possibly less competent) is less likely to add bugs.
 
If I feel this way about such an important “application”(!) then I should also professionally feel the same way about any production code I write. It’s a viewpoint that’s all. For me, after a few years of C and C++ I do not accept that terseness should necessarily be taken as a good thing for its own sake – especially when it’s someone else’s codeSigh | :sigh: Fine, when fast code is needed (say drivers, audio processing, graphics etc), but all I’m saying is that’s not what I want or expect from C#.
 
A competent optimising compiler should have a pretty good stab at optimising the longhand anyway. If not, and that important, I would suggest dropping down a level to C++, C or Assembler depending on your tastes.
 
I apologise if this seems “old school” (bit below the belt I feel – shame on you!)… one of the projects I worked on was team leader for the Right 3 computers flying the Boeing 777. This sharpens the mind somewhat and makes you try to make everything very obvious, spelt out and easily maintainable.
 
Also, your hint at “old school” is true. Started coding assembler in 1978, and coded many languages and app domains since and still feel I’m working on some leading edge stuff .NET 3, now 3.5 WPF, Workflow, LINQ etc and own a SW house of 40 people. In that, I don’t mind being considered “old School”!
 
You did say “I agree they shouldn't be thrown in without due care and attention” and actually I agree – but in moderation. The provision of terse operators can easily be abused by someone who can see them as a measure of their cleverness. Finally, this is not a big issue! It’s not the operator I mind, so much as the statement implying that “terse is better”… that I cannot agree with.

GeneralRe: An alternate viewmemberkschulz1 Oct '07 - 12:08 
Big Al 07 - I have to agree with you on this. While using this operator may make the code more concise (don't know about "beautifully"), it certainly makes it far less readable and harder to understand. Without some other clear benefit, I'm not seeing how that's a good thing. Interesting article though - didn't know this operator existed.
 
-kschulz

GeneralRe: An alternate viewmemberMatware1 Oct '07 - 16:24 
I've got to agree, I came across this operator back when the c# 2.0 language spec was released and went wow, that's as good as the "?:;" operator which I almost never use.
It’s a great operator, but is someone maintaining my code has to dive off to the language reference to fix a bug or add a feature I've failed as a developer.
 
As developers we have the heavy burden of writing code that performs a function (compiles to a working program) and clearly tells the story of what we were trying to achieve (without the need for comments, as they will always be derivative). This feature doesn't add anything to the earlier and reduces the quality of the later.
 
As for the issue of more code introduces errors, I think this is one off those off the cuff comments that has become so common that it hast lost all meaning. It refers to the complexity of the code as a function of the complexity of the problem, not size of your CS files as such. For example, writing a recursive XML node walker with hard coded element names instead of using XPath has a lot higher scope for error and will require more maintenance. While writing MissileControl.TestLaunchAllMissiles() instead MC.Go(false) has a lot less scope for error and someone unfamiliar with the code will have a good sense of what it does.
 


GeneralRe: An alternate viewmembergreenblob3 Oct '07 - 5:12 
Matware wrote:
...but is someone maintaining my code has to dive off to the language reference to fix a bug or add a feature I've failed as a developer

 
Depending upon your usages then I'd question if you have failed or whether they have - it's hardly difficult to comprehend the use of this operator, therefore I would say if they have to dive off to the language reference it is they that have failed to do their job.
 
If you had written something along the lines
 
a ?? b ?? c ?? d ?? e ?? "Hello World"
 
then yes, one could question your code but if it's something as simple as
 
a ?? "Hello World"
 
well it's a different issue altogether Smile | :)

GeneralRe: An alternate viewmemberreinux18 Oct '07 - 19:06 
Big Al 07 wrote:
If I want terse, then I’ll go back to assembler.

Terse means to be very expressive with very little spoken. Assembler is not terse by any stretch; in fact, it's verbose. Probably the most meaningfully verbose language, by design.
 
As for what you actually meant to say, which is that adding vocabulary decreases legibility, I'd say this one is justified. The idea that zero/empty/nothing/unassigned can be expressed by anything more than null is bad enough; allowing the developer to address that ambiguity and unify the concept of "null" in an atomic expression allows for the code to be read more at its intended level of abstraction, thus keeping the reader's train of thought on track.
 
Furthermore, I don't think this particular operator is as much of a pedagogical challenge as, say, nullable types, which requires the reader to not only know the operator but also understand new concepts. You'll only ever have to look it up once in your life (which takes less than a minute thanks to modern technology Unsure | :~ ) to appreciate it.
GeneralRe: An alternate viewmemberpeterchen5 Jan '08 - 10:25 
It all comes down to readability of the source code. Does the terse operator make the code more or less readable?
 
A terse construct can improve readability by expressing a common concept in a distinctive, non-redundant way, that can be conceived with least cognitive load. It can also worsen readability, by encoding an uncommon, yet complex construct in a simplistic, non-intuitive way.
 
For the operator in question, ther next best alternative to value ?? default would be either the ternary operator, value != null ? value : default;, or restructuring the code into an if/else block. Both introduce more code points to understand, and have an redundant occurance of value.
 
Worse, I could write code that looks like thi pattern, but isn't - either intentionally, or as a mistake:
object x = (Container.Matrix[i,j] != null) ? Container.Matrix[j,i] : Container.DefaultValue;
 


I don't think it's fair to compare assembler to this. Assembler has a completely different problem: the same idea can be expressed in many valid (and - depending on context preferrable) ways, e.g.

mov eax, [value]
or eax, eax
jz L1
mov eax, [default]
L1:

 
or by
 

xor ebx, ebx
mov esi, [v+ecx*0x04+0x20]
cmp esi, ebx
jne L1
mov [result], esi
jmp Exit
L1:
mov edi, [default]
mov [result], edi
Exit:

 
The cognitive load to recognize the idea from these snippets is fairly high.
 
We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
My first real C# project | Linkify!| FoldWithUs! | sighist


GeneralThis thing existed?!memberreinux29 Sep '07 - 9:12 
Crazy!
GeneralThanksmembergajatko29 Sep '07 - 0:19 
Although I use the ?? operator, thanks for this article. You gave me few new ideas which will help me in the future coding., like the foo ?? (foo = new List()); in a property getter or operator + to "access" a property of a null object. In such cases I used the "?:" statemnt.
By the way, it is debateble if creating an operator "
+" which would return Empty if an object is null is a good style coding (sometimes it is better to put a natural even if we are in the next bar*).
 
* - to code something explicitely, in this case to not force a potential reader to search for the operator's definition if it is so simple. Smile | :)
 
Greetings - Gajatko
 
Portable.NET is part of DotGNU, a project to build a complete Free Software replacement for .NET - a system that truly belongs to the developers.

GeneralA handy operatormemberlogan133728 Sep '07 - 11:50 
I too was surprised when I discovered this operator that it was not more commonly used. It is quite handy. However a note to your readers: the expression on either side of the ?? must evaluate to the same type. This is the one limitation of this operator as it doesn't allow for an object to be manipulated within the comparison.
 
For example, if you have a complex object and need to access a particular property of that object, you can't just say something like:
 
address.StreetName ?? "n/a"
 
...if address is null. Nor will
 
address ?? "n/a" work because that doesn't allow you to get the street name. Not the best example, just though of it off the top of my head.
 
* * *
 
To clarify what I mean here, I would rather the operator work on the basis that if the LHS equates to null OR throws a null reference exception, then the RHS will be used. But that's just me.
GeneralRe: A handy operatormemberDaniel Grunwald28 Sep '07 - 12:30 
logan1337 wrote:
address.StreetName ?? "n/a" ...if address is null.

 
It would be nice to have an operator that shortens "a != null ? a.B : null". It would be a lot more useful than ??.
Let's call it .?
Then your code would simply be ' address.?StreetName ?? "n/a" '. Shows address.StreetName if both address and address.StreetName at not null, otherwise it shows n/a.
For now, consider using the null object pattern if you find yourself writing "a != null ? a.B : null" (or the longer form using "if") a lot.
 

GeneralRe: A handy operatormemberlogan133728 Sep '07 - 13:01 
That's a neat idea, I quite like that. I'm always in favor of syntactical enhancements to make my job easier. Wink | ;)
 
Tho I would order it '?.' so as to imply that the object being "questioned" is the address object, while the following ".StreetName" is only to be applied if the object is not null, whereas if the object is null, evaluation skips ahead to the RHS of the ?? operator:
 
address?.StreetName ?? "n/a";
 
And if no properties are needed,
 
address? ?? "n/a"
 
...could be shortened to just
 
address ?? "n/a"
 
...as it is now.
 
Good idea. Smile | :)
GeneralRe: A handy operatormemberDaniel Grunwald29 Sep '07 - 0:18 
Yes, '?.' looks better than '.?'. Though '?.' would be a single operator, as just 'address?' makes no sense. So 'address? ?? "n/a"' would be invalid syntax.
In my program there a few places where I need use "a?.b?.c?.d" - such nested accesses get horribly messy without the ?. operator, so I had to use the null object pattern. But I think patterns are just workarounds for missing language features.
 

GeneralRe: A handy operatormemberTheCodeKing28 Sep '07 - 13:09 
It's a winner for me, also prefer ?. as opposed to .?. Would be nice to use in conventional if statements as well to save writting the extra check.
 
if (address?.StreetName==null)
{
// do this if address is null or address.StreetName is null
}
else
{
// do that
}
 

GeneralRe: A handy operator [modified]memberTheCodeKing28 Sep '07 - 13:24 
Just playing with implicit operators. Obviously not as good as a framework implementation, but you could almost pull it off. Unfortunately it doesn't look possible to add a new ? operator, so had to use + instead.
 
 public class Address
 {
    public string StreetName = null;
 
    public static bool operator +(Address address)
    {
       return address != null;
    }
  }
 
  string street = (+a)?a.StreetName:"n/a"; 

... or another interesting play on operators...
 
 public class Address
 {
    private static Address Empty = new Address();
    public string StreetName = null;
 
    public static Address operator +(Address address)
    {
       return address ?? Empty
    }
  }
 
  string street = (+a).StreetName ?? "n/a";
 
-- modified at 19:48 Friday 28th September, 2007
 

GeneralRe: A handy operatormemberTheCodeKing28 Sep '07 - 12:42 
I guess you could say
 
string street = address==null ? new Address().StreetName : address.StreetName ?? "n/a";
 
but whether thats's helpful for others is debatable Smile | :)
 

GeneralRe: A handy operatormemberTheCodeKing28 Sep '07 - 12:44 
or hows about...
 
string street = (address ?? new Address()).StreetName ?? "n/a";
 

GeneralRe: A handy operatormemberlogan133728 Sep '07 - 12:56 
Yeah I considered that too. Hardly ideal tho as it involves creating a new object which could potentially involve a lot of overhead. Not to mention it only works if the object has a default constructor AND initializes the fields to null.
GeneralRe: A handy operatormemberTheCodeKing28 Sep '07 - 13:02 
Yes, I think Daniel had the best idea with the feature request
 
string street = address?.StreetName ?? "n/a";
 

GeneralRe: A handy operatormemberJoshuaMcKinney6 Oct '07 - 20:39 
Why not use the null object pattern?, i.e. if something can be empty meaningfully, indicate this in code
public class Street
{
    public static readonly Street Empty = new Street("n/a");
 
    private string value;
    public Street(string value)
    {
        this.value = value;
    }
 
    public override string ToString()
    {
        return value;
    }
}
 
public class Address
{
    public static readonly Address Empty = new Address(Street.Empty);
 
    private Street street = Street.Empty;
    public Street Street
    {
        get { return street; }
    }
	
    public Address(Street street)
    {
        this.street = street;
    }
}
Then you could instead of use:
Address address = null;
Console.WriteLine((address ?? Address.Empty).Street);
or even better never set the address to a meaningless null value:
Address address = Address.Empty;
Console.WriteLine(address.Street);
This also allows the ability to capture with more detail several unknown conditions.
E.g.
1. The user has not yet specified the address
2. The user has no fixed address
3. The user does not know the address
...
 
For each of these it would be reasonable to replace Street.Empty with another static readonly field (Street.NotSpecified, Street.Unknown, Street.NoFixedAddress, ...). We can then use the Street.ToString() directly or easily compare to those static fields if there is specific logic needed in the application.
our code becomes even more descriptive now:
Address address = Address.NotSpecified
 
I don't like the op + on address in the article. Syntactically great - you save a bunch of characters; however, semantically the positive of an address doesn't mean anything and only adds to a maintenance programmer's pain in having to deal with your app.
GeneralRe: A handy operatormemberlogan13378 Oct '07 - 7:42 
Yes I like the idea of providing more information representing the state of an object instead of just "null" which could mean several things, as you've illustrated. I think what we were really getting at here is that it would be convenient to have a syntactic means of checking whether or not a particular object was "not null", or in other words if it had a proper value.
 
I also don't like using symbols like + arbitrarily to represent operations, however this is also partly the fault of Microsoft for not allowing much flexibility when it comes to operator overloading in C#. It would really be nice if we could define our own symbols and combinations of symbols to mean certain syntactic things--then we could define the '?.' operator ourselves, for instance.
 
Unfortunately, we currently have to rely on MS to do this for us.
GeneralRe: A handy operatormemberTheCodeKing8 Oct '07 - 8:17 
That's right, I wasn't suggesting anyone use the (+) implementation from the example. I was seeing how close I could get to the imaginary null checking .? synatax we discussed in the thread eariler by messing with operators.

The JoshuaMcKinney example is much more the sort of code you might use in the real world, depending of course on the desired behaviour of the app.

 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 28 Sep 2007
Article Copyright 2007 by TheCodeKing
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid