Andrew, I really like that idea. Turning back to the null coalescing operator (spelled ?? in other languages), how do you think that fits in? 

Consider this syntax:

>>> None? or 1
1

This works if NoneQuestion overrides __nonzero__ to return False.

>>> 0? or 1
0

This doesn't work, because 0? returns 0, and "0 or 1" is 1. 

We could try this instead, if NoneQuestion overrides __or__:

>>> 0? | 1
0
>>> 0 ?| 1
0

This looks a little ugly, and it would be nice (as MRAB pointed out) if null coalescing short circuited.

>>> None? or None?

This also doesn't work quite right. If both operands are None, we want the expression to evaluate to None, not NoneQuestion. Should null coalescing be a separate operator? And if so, are "?" and "??" too similar?

Can anybody think of realistic use cases for overriding a magic method for the "?" operator? I would like to include such use cases in a PEP. One possible use case: being able to coalesce empty strings.

>>> s1 = MyString('')
>>> s2 = MyString('foobar')
>>> s1? or s2
MyString('foobar')



On Fri, Sep 18, 2015 at 9:10 PM, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
On Sep 18, 2015, at 18:00, Chris Angelico <rosuav@gmail.com> wrote:
>
>> On Sat, Sep 19, 2015 at 10:49 AM, Andrew Barnert <abarnert@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.


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



--
Mark E. Haase
202-815-0201