Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unique ways to use the null coalescing operator [closed]

People also ask

What is the use of null-coalescing operator?

The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null ; otherwise, it evaluates the right-hand operand and returns its result.

What is null-conditional and null coalescing?

In cases where a statement could return null, the null-coalescing operator can be used to ensure a reasonable value gets returned. This code returns the name of an item or the default name if the item is null. As you can see, this operator is a handy tool when working with the null-conditional operator.

When was Nullish coalescing operator added?

JavaScript made sure this can be handled with its nullish operator also known as the Null Coalescing Operator, which was added to the language with ECMAScript 2020. With it, you can either return a value or assign it to some other value, depending on a boolean expression.

Is Nullish undefined?

A nullish value is a value that is either null or undefined .


Well, first of all, it's much easier to chain than the standard ternary operator:

string anybody = parm1 ?? localDefault ?? globalDefault;

vs.

string anyboby = (parm1 != null) ? parm1
               : ((localDefault != null) ? localDefault
               : globalDefault);

It also works well if a null-possible object isn't a variable:

string anybody = Parameters["Name"]
              ?? Settings["Name"]
              ?? GlobalSetting["Name"];

vs.

string anybody = (Parameters["Name"] != null ? Parameters["Name"]
                 : (Settings["Name"] != null) ? Settings["Name"]
                 :  GlobalSetting["Name"];

I've used it as a lazy load one-liner:

public MyClass LazyProp
{
    get { return lazyField ?? (lazyField = new MyClass()); }
}

Readable? Decide for yourself.


I've found it useful in two "slightly odd" ways:

  • As an alternative for having an out parameter when writing TryParse routines (i.e. return the null value if parsing fails)
  • As a "don't know" representation for comparisons

The latter needs a little bit more information. Typically when you create a comparison with multiple elements, you need to see whether the first part of the comparison (e.g. age) gives a definitive answer, then the next part (e.g. name) only if the first part didn't help. Using the null coalescing operator means you can write pretty simple comparisons (whether for ordering or equality). For example, using a couple of helper classes in MiscUtil:

public int Compare(Person p1, Person p2)
{
    return PartialComparer.Compare(p1.Age, p2.Age)
        ?? PartialComparer.Compare(p1.Name, p2.Name)
        ?? PartialComparer.Compare(p1.Salary, p2.Salary)
        ?? 0;
}

Admittedly I now have ProjectionComparer in MiscUtil, along with some extensions, which make this kind of thing even easier - but it's still neat.

The same can be done for checking for reference equality (or nullity) at the start of implementing Equals.


Another advantage is that the ternary operator requires a double evaluation or a temporary variable.

Consider this, for instance:

string result = MyMethod() ?? "default value";

while with the ternary operator you are left with either:

string result = (MyMethod () != null ? MyMethod () : "default value");

which calls MyMethod twice, or:

string methodResult = MyMethod ();
string result = (methodResult != null ? methodResult : "default value");

Either way, the null coalescing operator is cleaner and, I guess, more efficient.


Another thing to consider is that the coalesce operator doesn't call the get method of a property twice, as the ternary does.

So there are scenarios where you shouldn't use the ternary operator, for example:

public class A
{
    var count = 0;
    private int? _prop = null;
    public int? Prop
    {
        get 
        {
            ++count;
            return _prop
        }
        set
        {
            _prop = value;
        }
    }
}

If you use:

var a = new A();
var b = a.Prop == null ? 0 : a.Prop;

the getter will be called twice and the count variable will be equal to 2, and if you use:

var b = a.Prop ?? 0

the count variable will be equal to 1, as it should.