[Python-ideas] Null coalescing operators

Andrew Barnert abarnert at yahoo.com
Sat Sep 19 05:20:49 CEST 2015

On Sep 18, 2015, at 18:52, MRAB <python at mrabarnett.plus.com> wrote:
>> 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?

You're right; I didn't think about that. But I don't think that's a problem. 

I believe C#, Swift, etc. all evaluate the arguments in their equivalent. And languages like ObjC that do automatic nil coalescing for all method calls definitely evaluate them. If you really want to switch on spam and not call sing_lumberjack_song, you can always do that manually, right?

> 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)".

That actually makes sense just for its own reasons.

Actually, now that I think about it, the way I defined it above already gives you think: if spam? is spam if it's anything but None, then spam?? is always spam?, right?

> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/

More information about the Python-ideas mailing list