[Python-ideas] Null coalescing operators
Stephen J. Turnbull
stephen at xemacs.org
Mon Sep 21 10:48:28 CEST 2015
Mark E. Haase writes:
> This conversation has really focused on the null aware attribute access,
> but the easier and more defensible use case is the null coalesce operator,
> spelled "??" in C# and Dart. It's easy to find popular packages that use
> something like "retries = default if default is not None else cls.DEFAULT"
To me, it's less defensible. Eg, currently TOOWTDI for "??" is the
idiom quoted above. I sorta like the attribute access, attribute
fetch, and function call versions, though I probably won't use them.
Also some functions need to accept None as an actual argument, and the
module defines a module-specific sentinel. The inability to handle
such sentinels is a lack of generality that the "x if x is not
sentinel else y" idiom doesn't suffer from, so "??" itself can't
I don't write "def foo(default):" (ever that I can recall), so using
retries = default if default is not None else cls.DEFAULT
confuses me. Realistically, I would be writing
retries = retries if retries is not None else cls.RETRIES
(or perhaps the RHS would be "self.retries"). That doesn't look that
bad to me (perhaps from frequent repetition). It's verbose, but I
don't see a need to chain it, unlike "?.". For "?.", some Pythonistas
would say "just don't", but I agree that often it's natural to chain.
> to supply default instances. Other packages do something like
> "retries = default or cls.DEFAULT", which is worse because it
> easy to overlook the implicit coalescing of the left operand.
Worse? It's true that it's more risky because it's all falsies, not
just the None sentinel, but I think "consenting adults" applies here.
I don't know about the packages you looked at, but I often use
"x = s or y" where I really want to trap the falsey value of the
expected type, perhaps as well as None, and I use the "x if s is not
sentinel else y" idiom to substitute default values. I also use "or"
in scripty applications and unit test setup functions where I want
compact expression and I don't expect long-lived objects to be passed
so I can easily figure out where the non-None falsey came from anyway.
> A) Is coalesce a useful feature? (And what are the use cases?)
Yes, for the whole group of operators. Several use cases for the
other operators have already been proposed, but I wouldn't use them
myself in current or past projects, and don't really foresee that
changing. -0 for the group on the IAGNI principle.
But for "??" specifically, it's just more compact AFAICS. I don't see
where I would use x ?? y ?? z, so the compactness doesn't seem like
that great a benefit. In practice, I think the use cases for "??"
would be a strict subset of the use cases for the ternary operator, so
you have to argue that "this special case *is* special enough" to have
its own way to do it. I don't think it is. -1
> C) If it should be an operator, is "??" an ugly spelling?
> >>> retries = default ?? cls.DEFAULT
Looks like metasyntax from pseudo-code that didn't get fixed to me.
That would probably change if other ?x operators were added though.
I have no comment on short-circuiting (no relevant experience), or
keyword vs. punctuation spellings. On second thought:
> D) If it should be an operator, are any keywords more aesthetically
> pleasing? (I expect zero support for adding a new keyword.)
> >>> retries = default else cls.DEFAULT
I kinda like this if-less else syntax for the symmetry with else-less
if. But on second thought I think it would persistently confuse me
when reading, because it would be extremely natural to expect it to be
another way of spelling "default or cls.DEFAULT". "try ... else ..."
also has its attraction, but I suppose that would fail for the same
reasons that the ternary operator is spelled "x if y else z" rather
than "if y then x else z".
More information about the Python-ideas