[Python-ideas] Null coalescing operators
steve at pearwood.info
Mon Sep 21 16:41:31 CEST 2015
On Mon, Sep 21, 2015 at 11:55:55AM +0100, Paul Moore wrote:
> On 21 September 2015 at 03:35, Mark E. Haase <mehaase at gmail.com> wrote:
> > A) Is coalesce a useful feature? (And what are the use cases?)
> There seem to be a few main use cases:
> 1. Dealing with functions that return a useful value or None to signal
> "no value". I suspect the right answer here is actually to rewrite the
> function to not do that in the first place. "Useful value or None"
> seems like a reasonable example of an anti-pattern in Python.
I think that's a bit strong. Or perhaps much too strong.
There are times where you can avoid the "None or value" pattern, since
there is a perfectly decent empty value you can use instead of None.
E.g. if somebody doesn't have a name, you can use "" instead of None,
and avoid special treatment.
But that doesn't always work. Suppose you want an optional (say) Dog
object. There isn't such a thing as an empty Dog, so you have to use
some other value to represent the lack of Dog. One could, I suppose,
subclass Dog and build a (singleton? borg?) NoDog object, but that's
overkill and besides it doesn't scale well if you have multiple types
that need the same treatment.
So I don't think it is correct, or helpful, to say that we should avoid
the "None versus value" pattern. Sometimes we can naturally avoid it,
but it also has perfectly reasonable uses.
> Overall, I don't think coalesce is *that* useful, given that it seems
> like it'd mainly be used in situations where I'd recommend a more
> strategic fix to the code.
Go back to the original use-case given, which, paraphrasing, looks
something like this:
result = None if value is None else value['id'].method()
I don't think we can reject code like the above out of hand as
un-Pythonic or an anti-pattern. It's also very common, and a little
verbose. It's not bad when the value is a name, but sometimes it's an
expression, in which case it's both verbose and inefficient:
result = None if spam.eggs(cheese) is None else spam.eggs(cheese)['id'].method()
result = spam.eggs(cheese)?['id'].method()
which only calculates the expression to the left of the ?[ once.
An actual real-life example where we work around this by using a
temporary name that otherwise isn't actually used for anything:
mo = re.match(needle, haystack)
substr = mo.group()
substr = None
I think it is perfectly reasonable to ask for syntactic sugar to avoid
having to write code like the above:
substr = re.match(needle, haystack)?.group()
That's not to say we necessarily should add sugar for this, since
there is no doubt there are disadvantages as well (mostly that many
people dislike the ? syntax), but in principle at least it would
certainly be nice to have and useful.
> > B) If it is useful, is it important that it short circuits? (Put another
> > way, could a function suffice?)
> Short circuiting is important, but to me that simply implies that the
> "useful value or None" approach is flawed *because* it needs
> short-circuiting to manage.
Nothing needs short-circuiting, at least in a language with imperative
assignment statements. You can always avoid the need for short-circuits
with temporary variables, and sometimes that's the right answer: not
everything needs to be a one-liner, or an expression.
But sometimes it is better if it could be.
> > C) If it should be an operator, is "??" an ugly spelling?
> > >>> retries = default ?? cls.DEFAULT
I assume the ?? operator is meant as sugar for:
retries = cls.DEFAULT if default is None else default
I prefer to skip the "default" variable and use the standard idiom:
if retries is None:
retries = cls.DEFAULT
I also worry about confusion caused by the asymmetry between ?? and the
other three ? cases:
# if the left side is None, return None, else evaluate the right side
# if the left side is None, return the right side, else return the left
spam ?? eggs
but perhaps I'm worried over nothing.
More information about the Python-ideas