[Python-ideas] Null coalescing operators

MRAB python at mrabarnett.plus.com
Sat Sep 19 03:52:08 CEST 2015

On 2015-09-19 02:39, MRAB wrote:
> On 2015-09-19 02:10, Andrew Barnert via Python-ideas wrote:
>> On Sep 18, 2015, at 18:00, Chris Angelico <rosuav at gmail.com> wrote:
>>>> On Sat, Sep 19, 2015 at 10:49 AM, Andrew Barnert <abarnert at yahoo.com> 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.
>>>> Next, "spam?.cheese?" returns something with a __call__ method that just passed through to spam?.cheese.__call__, except that on NoneType it returns something with a __call__ that always returns None. That solves the cheese case.
>>> Hang on, how do you do this? How does the operator know the difference
>>> between "spam?", which for None has to have __getattr__ return None,
>>> and "spam?.cheese?" that returns (lambda: None)?
>>>>> spam
>> None
>>>>> spam?
>> NoneQuestion
>>>>> spam?.cheese
>> None
>>>>> spam?.cheese?
>> NoneQuestion
>>>>> spam?.cheese?()
>> None
>> All you need to make this work is:
>> * "spam?" returns NoneQuestion if spam is None else spam
>> * NoneQuestion.__getattr__(self, *args, **kw) returns None.
>> * NoneQuestion.__call__(self, *args, **kw) returns None.
>> Optionally, you can add more None-returning methods to NoneQuestion. Also, whether NoneQuestion is a singleton, has an accessible name, etc. are all bikesheddable.
>> I think it's obvious what happens is "spam" is not None and "spam.cheese" is, or of both are None, but if not, I can work them through as well.
> I see it as "spam? doing "Maybe(spam)" and then attribute access
> checking returning None if the wrapped object is None and getting the
> attribute from it if not.
> I think that the optimiser could probably avoid the use of Maybe in
> cases like "spam?.cheese".
I've thought of another issue:

If you write "spam?(sing_lumberjack_song())", won't it still call
sing_lumberjack_song even if spam is None? After all, Python evaluates
the arguments before looking up the call, so it won't know that "spam"
is None until it tries to call "spam?".

That isn't a problem with "spam.sing_lumberjack_song() if spam is not
None else None" or if it's optimised to that, but "m = spam?;
m(sing_lumberjack_song())" is a different matter.

perhaps a "Maybe" object should also support "?" so you could write "m
= spam?; m?(sing_lumberjack_song())". "Maybe" could be idempotent, so
"Maybe(Maybe(x))" returns the same result as "Maybe(x)".

More information about the Python-ideas mailing list