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.
Python generally doesn't special-case None, so having a bit of magic that works only on that one object seems a little odd. For comparison purposes, Pike has something very similar to what you're describing, but Pike *does* treat the integer 0 as special, so it makes good sense there. Pike code that wants to return "a thing or NULL" will return an object or the integer 0, where Python code will usually return an object or None. I can't think of any situation in Python where the language itself gives special support to None, other than it being a keyword. You're breaking new ground.
But in my opinion, the practicality is worth it. The use of None to represent the SQL NULL value , the absence of useful return value, or other "non-values", is pretty standard. I would define the operator pretty much the way you did above, with one exception. You say:
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:
1) Make None callable. None.__call__(*a, **ka) always returns None. 2) 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.
 Or non-value, depending on context