[Python-ideas] Null coalescing operators

Steven D'Aprano steve at pearwood.info
Sat Sep 19 05:41:12 CEST 2015


On Sat, Sep 19, 2015 at 12:02:42AM +0100, MRAB wrote:

> To me, the choice _is_ obvious: "obj?[idx]". After all, that's more in
> keeping with "obj?.attr" and "func?()".
> 
> If you had "obj?[idx]", then shouldn't it also be "obj.?attr" and
> "func(?)"?

No.

If I understand the idea, obj?.attr returns None if obj is None, 
otherwise returns obj.attr. The question mark (shrug operator?) applies 
to `obj` *before* the attribute lookup, so it should appear *before* the 
dot (since we read from left-to-right).

The heuristic for remembering the order is that the "shrug" (question 
mark) operator applies to obj, so it is attached to obj, before any 
subsequent operation.

For the sake of brevity, using @ as a placeholder for one of attribute 
access, item/key lookup, or function call, then we have:

    obj?@

as syntactic sugar for:

    None if obj is None else obj@

Furthermore, we should be able to chain a sequence of such @s:

paperboy.receive(customer?.trousers.backpocket.wallet.extract(2.99))


being equivalent to:

paperboy.receive(None if customer is None else 
                 customer.trousers.backpocket.wallet.extract(2.99) 
                 )


Let's just assume we have a good reason for chaining lookups that isn't 
an egregious violation of the Law of Demeter, and not get into a debate 
over OOP best practices, okay? :-)

Suppose that wallet itself may also be None. Then we can easily deal 
with that situation too:

paperboy.receive(customer?.trousers.backpocket.wallet?.extract(2.99))


which I think is a big win over either of these two alternatives:

# 1
paperboy.receive(None if customer is None else 
                 None if customer.trousers.backpocket.wallet is None 
                 else customer.trousers.backpocket.wallet.extract(2.99) 
                 )

# 2
if customer is not None:
    wallet = customer.trousers.backpocket.wallet
    if wallet is not None:
        paperboy.receive(wallet.extract(2.99))


It's a funny thing, I'm usually not a huge fan of symbols outside of 
maths operators, and I strongly dislike the C ? ternary operator, but 
this one feels really natural to me. I didn't have even the most 
momentary "if you want Perl, you know where to find it" thought.



-- 
Steve


More information about the Python-ideas mailing list