On 2015-09-18 23:37, Chris Angelico wrote:
On Sat, Sep 19, 2015 at 3:42 AM, Mark Haase email@example.com wrote:
StackOverflow has many questions on the topic of null coalescing operators in Python, but I can't find any discussions of them on this list or in any of the PEPs. Has the addition of null coalescing operators into Python ever been discussed publicly?
Python has an "or" operator that can be used to coalesce false-y values, but it does not have an operator to coalesce "None" exclusively.
created?.isoformat() # is equivalent to created.isoformat() if created is not None else None
but this means there needs to be some magic, because it should be equally possible to write:
created?.year # equivalent to created.year if created is not None else None
which means that sometimes it has to return None, and sometimes (lambda *a,**ka: None). Three possible solutions:
- Make None callable. None.__call__(*a, **ka) always returns None.
- Special-case the immediate call in the syntax, so the equivalencies
are a bit different. 3) Add another case: func?(args) evaluates func, and if it's None, evaluates to None without calling anything.
Option 1 would potentially mask bugs in a lot of unrelated code. I don't think it's a good idea, but maybe others disagree.
Option 2 adds a grammatical distinction that currently doesn't exist. When you see a nullable attribute lookup, you have to check to see if it's a method call, and if it is, do things differently. That means there's a difference between these:
func = obj?.attr; func() obj?.attr()
Option 3 requires a bit more protection, but is completely explicit. It would also have use in other situations. Personally, I support that option; it maintains all the identities, is explicit that calling None will yield None, and doesn't need any magic special cases. It does add another marker, though:
created?.isoformat?() # is equivalent to created.isoformat() if created is not None and created.isoformat is not None else None
As to the syntax... IMO this needs to be compact, so ?. has my support. With subscripting, should it be "obj?[idx]" or "obj[?idx]" ? FWIW Pike uses the latter, but if C# uses the former, there's no one obvious choice.
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(?)"?