[Python-ideas] PEP 505 (None coalescing operators) thoughts

Andrew Barnert abarnert at yahoo.com
Wed Sep 30 01:53:58 CEST 2015

On Sep 29, 2015, at 14:48, Terry Reedy <tjreedy at udel.edu> wrote:
>> On 9/29/2015 12:35 PM, Sven R. Kunze wrote:
>>> On 29.09.2015 02:38, Terry Reedy wrote:
>>>> On 9/28/2015 5:48 PM, Luciano Ramalho wrote:
>>>> Glyph tweeted yesterday that everyone should watch the "Nothing is
>>>> Something" 35' talk by Sandi Metz at RailsConf 2015. It's great and,
>>>> in a way, relevant to this discussion.
>>>> https://www.youtube.com/watch?v=29MAL8pJImQ
>>> I understood Metz as advocation avoidig the nil (None) problem by
>>> giving every class an 'active nothing' that has the methods of the
>>> class.  We do that for most builtin classes -- 0, (), {}, etc. She
>>> also used the identity function with a particular signature in various
>>> roles.
>> I might stress here that nobody said there's a single "active nothing".
> Ruby's nil and Python's None are passibe nothings.  Any operation other than those inherited from Object raise an exception.
>> There are far more "special case objects" (as Robert C. Martin calls it)
>> than 0, (), {}, etc.
> Metz's point is that there is potentially one for most classes than one might write.

I don't think this is true.

First, "int" and "float" are such general-use/low-semantics types that "0" or "0.0" doesn't always mean "nothing". If you're talking about counts, or distances from some preferred origin, then yes, 0 is nothing; if you're talking about Unix timestamps, or ratings from 0 to 5 stars, then it's not. That's exactly why there's so much code in C and such languages that passes around -1 for nothing (but of course that only works when your real data is unsigned but small enough to waste a bit using a signed int), and the fact that Python idiomatically uses None instead of -1 is a strength, not a weakness. Likewise, sometimes "" makes a perfectly good null string, but sometimes it doesn't—it's often worth distinguishing between "" (has no middle name) and None (we haven't asked for the middle name yet), for example.

Also, list, set, dict, and most user-defined types are mutable. This means that using [] or Spam() as a type-specific nothing means your nothings are distinct, mutable objects. Sometimes that's OK, sometimes it's even explicitly a good thing, but sometimes it definitely isn't.

In a language that encouraged use of more finely-grained types (so you never use "int", you use "Rating", which is constrained to 0-5), the idea that each type that's nullable should have its own null makes some sense, and even more so for a pure-immutable language and idioms around type-driven programming. But that's not even close to Python.

> Some people have wondered why Python does not come with a builtin identity function.  The answer has been that one is not needed much and and it is easy to create one.  Metz's answer is that they are very useful for generalizing classes.  But she also at least implied that they should be specific to each situation.  Certainly in Python, if code were to check signature, and even type annotation, then a matching id function would be needed.

Having to create an identity function for each type seems like a horrible idea. Even more so in a language that encourages granular typing.

Fortunately, any such language that anyone would actually use probably has parametric genericity, so you could just write a single id function from any type A to the same A, and let the compiler deal with specializing it for each type instead of the programmer. (Or you could make type class definitions provide an id by default, or something else equivalent.)

>> I fear, however, the stdlib cannot account for
> > every special case object possible.
> Right.  It is not possible to create a null instance of a class that does not yet exist.
>> Without None available in the first place,
> The problem of a general object is that it is general.  It should either be a ghost that does nothing, as with None, or a borg than does everything, as with the Bottom of some languages.

It might be worth having both. But maybe not—personally, while I've occasionally created a Python-like ghost in Smalltalk, I've never wanted a Smalltalk-like borg in Python. What I have wanted, quite often, is to write code that locally, explicitly, treats the ghost as a borg. And that's exactly what "is not None" tests are for, and we've all used them. This proposal isn't adding the concept to the language or idiom, just providing syntactic sugar to make an already widely-used feature easier to use.

> >  users would be forced to create their domain-specific special
> > case objects.
> Metz recomends doing this voluntarily ;-)
> perhaps after an initial prototype.
> > None being available though, people need to be taught to avoid it,
> > which btw. she did a really good job of.
> I think None works really well as the always-returned value for functions that are really procedures.  The problem comes with returning something or None, versus something or raise, or something or null of the class of something.

I think the problem comes with assuming that there is a universal answer here. Sometimes something vs. None is appropriate. Sometimes, raising is appropriate. Sometimes, returning a special value is appropriate. Occasionally, even building a Maybe type and using that (with or without collapsing) is appropriate (even without syntactic support for pattern matching and fmapping, although it's much nicer with...). Python idiomatically uses all of the first three extensively, differently in different situations, but rarely the fourth. Some languages use a different subset.

Suggesting that one of these must always be the answer doesn't seem to be motivated by any real concerns. Does Python code really have a lot more problems with this than C or Swift or some other language that only idiomatically uses one or two different answers for? Even if it does (which I doubt), would eliminating one of the three but changing as little else as possible about the language and ecosystem actually help? And would it be even remotely feasible to do so?

More information about the Python-ideas mailing list