[Python-ideas] Null coalescing operators

Steven D'Aprano steve at pearwood.info
Sat Sep 19 07:06:48 CEST 2015

On Fri, Sep 18, 2015 at 05:49:36PM -0700, Andrew Barnert via Python-ideas wrote:

> Obviously "spam?" returns something with a __getattr__ method that 
> just passes through to spam.__getattr__, except that on NoneType it 
> returns something with a __getattr__ that always returns None. That 
> solves the eggs case.

Ah, and now my enthusiasm for the whole idea is gone...

In my previous response, I imagined spam?.attr to be syntactic sugar for 
`None if spam is None else spam.attr`. But having ? be an ordinary 
operator that returns a special Null object feels too "Design Pattern-y" 
to me. I think the Null design pattern is actually harmful, and I would 
not like to see this proposal implemented this way.

(In another email, Andrew called the special object something like 
NoneMaybe or NoneQuestion, I forget which. I'm going to call the object 
Null, since that's less typing.)

The Null object pattern sounds like a great idea at first, but I find it 
to be a code smell at best and outright harmful at worst. If you are 
passing around an object which is conceptually None, but unlike None 
reliably does nothing without raising an exception no matter what you do 
with it, that suggests to me that something about your code is not 

If your functions already accept None, then you should just use None. If 
they don't accept None, then why are you trying to smuggle None into 
them using a quasi-None that unconditionally hides errors?

Here are some problems with the Null pattern as I see it:

(1) Suppose that spam? returns a special Null object, and Null.attr 
itself returns Null. (As do Null[item] and Null(arg), of course.) This 
matches the classic Null object design pattern, and gives us chaining 
for free:

    value = obj?.spam.eggs.cheese

But now `value` is Null, which may not be what we expect and may in fact 
be a problem if we're expecting it to be "an actual value, or None" 
rather than our quasi-None Null object.

Because `value` is now a Null, every time we pass it to a function, we 
risk getting new Nulls in places that shouldn't get them. If a function 
isn't expecting None, we should get an exception, but Null is designed 
to not raise exceptions no matter what you do with it. So we risk 
contaminating our data with Nulls in unexpected places.

Eventually, of course, there comes a time where we need to deal with the 
actual value. With the Null pattern in place, we have to deal with two 
special cases, not one:

    # I assume Null is a singleton, otherwise use isinstance
    if filename is not None and filename is not Null:

A small nuisance, to be sure, but part of the reason why I really don't 
think much of the Null object pattern. It sounds good on paper, but I 
think it's actually more dangerous and inconvenient than the problem it 
tries to solve.

(2) We can avoid the worst of the Null design (anti-)pattern by having 
Null.attr return None instead of Null. Unfortunately, that means we've 
lost automatic chaining. If you have an object that might be None, we 
have to explicitly use the ? operator after each lookup except the last:

    value = obj?.spam?.eggs?.cheese

which is (a) messy, (b) potentially inefficient, and (c) potentially 
hides subtle bugs.

Here is a scenario where it hides bugs. Suppose obj may be None, but if 
it is not, then obj.spam *must* be a object with an eggs attribute. If 
obj.spam is None, that's a bug that needs fixing. Suppose we start off 
by writing the obvious thing:


but that fails because obj=None raises an exception:

    obj? returns Null
    Null.spam returns None
    None.eggs raises

So to protect against that, we might write:


but that protects against too much, and hides the fact that obj.spam 
exists but is None.

As far as I am concerned, any use of a Null object has serious 
downsides. If people want to explicitly use it in their own code, well, 
good luck with that. I don't think Python should be making it a 

I think the first case, the classic Null design pattern, is actually 
*better* because the downsides are anything but subtle, and people will 
soon learn not to touch it with a 10ft pole *wink*, while the second 
case, the "Null.attr gives None" case, is actually worse because it 
isn't *obviously* wrong and can subtly hide bugs.

How does my earlier idea of ? as syntactic sugar compare with those?

In that case, there is no special Null object, there's only None. So we 
avoid the risk of Null infection, and avoid needing to check specially 
for Null. It also avoids the bug-hiding scenario:


is equivalent to:

    None if obj is None else obj.spam.eggs

If obj is None, we get None, as we expect. If it is not None, we get 
obj.spam.eggs as we expect. If obj.spam is wrongly None, then we get an 
exception, as we should.


More information about the Python-ideas mailing list