Adding None-aware operators to Python?
A PEP that has been around for a while, without being either accepted or rejected, was reintroduced recently on the python-ideas mailing list. PEP 505 ("None-aware operators") would provide some syntactic sugar, in the form of new operators, to handle cases where variables might be the special None value. It is a feature that other languages support, but has generally raised concerns about being "un-Pythonic" over the years. At this point, though, the Python project still needs to figure out how it will be governed—and how PEPs can be accepted or rejected.
None-awareness
The basic idea is fairly straightforward. Patterns like the following:
if x is None: x = 42could be replaced with a more compact, and possibly more readable, version:
x = x ?? 42or the even more compact:
x ??= 42So, two new operators would be defined. The first is "??", which returns the left-hand side if it is not None and the right-hand side otherwise; importantly, it does not evaluate the right-hand side at all unless the left side is None. As with other "augmented assignment" operators (e.g. +=), "??=" simply applies the ?? operator to the two arguments and assigns the result to the left-hand side.
In that same vein, None-aware indexing and attribute-access operators can change code like the following:
if x is not None and x['foo'] == 'bar': ... if y is not None and y.foo == 'bar': ...to:
if x?['foo'] == 'bar': ... if y?.foo == 'bar': ...The operators can, of course, be combined, as the following example from the PEP shows. The first line is an expression from the email/generator.py file in the standard library, while the second is a rewrite using the new operators:
mangle_from_ = True if policy is None else policy.mangle_from_ mangle_from_ = policy?.mangle_from_ ?? True
Readers who think some or all of that looks more like Perl—or, more
pejoratively, like line noise—than Python are not alone. That is probably
one of the most common complaints heard after Steve Dower reintroduced the PEP in mid-July (as well as
in previous discussions of the PEP). In that
message, he noted that it might not be the best time to bring up the PEP, given
the fact that there was no agreed-upon way for the PEP to be
accepted (or, for that matter, rejected) since the recent resignation of
Guido van Rossum; "but since we're
likely to argue for a while anyway it probably can't hurt (and maybe this
will become the test PEP for whoever takes the reins?).
"
"Argue for a while" is what followed. Many were simply opposed to any of the operators, largely because of their supposed un-Pythonic nature. But some were more open to just adding ?? (and ??=); the None-aware indexing and attribute-access operators (?[] and ?., also known as "maybe-subscript" and "maybe-dot") can be strung together in ways that seem potentially confusing so folks seemed more wary of them. There are also differing opinions on the readability of the resulting "one-liners"—even advocates of the new operators do not seem inclined toward using them willy-nilly.
Spelling
Many of the arguments against the operators boil down to how they are "spelled"; this is the root of the "un-Pythonic/Perl-like/line-noise" argument. But that's only part of the discussion—or should be. If there is utility to replacing the canonical way to default a variable, how to spell the operator (or keyword) should be a secondary consideration; as Steven D'Aprano put it:
That's not to say that spelling is not important *at all*, or that we should never prefer words to symbols. But if the only objection we have is "this is useful but I don't like the spelling so -1" then that's usually a pretty weak argument against the feature.
Giampaolo Rodolà is concerned that most of the new operators are not "explicit", effectively arguing that they run aground on the "explicit is better than implicit" guideline in The Zen of Python. As he put it:
D'Aprano argued that any new operators are going to have to look somewhat
strange since all of the non-strange operators are already in use. Rodolà
said that was part of his point: "Not to state the obvious but it's
not that we *have to* use the remaining unused symbols just because
they're there.
" David Mertz went even
further, arguing that the PEP 572
approval has pushed things too far:
I was consistently +0 on the 572 idea, as long as its worst excesses were trimmed, as in the final PEP. But after reading this discussion, I almost reconsider that opinion since its social effect seems to be a move towards accepting wild and unnecessary changes that "might be useful" for a few unusual programming patterns.
The argument over the explicitness of the new operators spawned a huge sub-thread, where it was pretty clear that no minds were being changed. Rodolà argued that the implicit check for None used by the operators makes them non-explicit. On the other hand, D'Aprano argued that if the operators are defined to do a particular thing, then using them that way is explicit. The whole argument caused him to proclaim:
Nicholas Chammas observed that perhaps it was not a difference of explicit versus implicit, but instead related to something that C++ inventor Bjarne Stroustrup once said:
> For new features, people insist on LOUD explicit syntax.
> For established features, people want terse notation.
I think the "explicit vs. implicit" part of this discussion is probably better expressed as a discussion about "loud vs. terse" syntax. None of the operators in PEP 505 have implicit behavior, to the best of my understanding. It's just that the operators are new and have terse spellings.
Limbo
Along the way, Dower tried to refocus the discussion by presenting some of the arguments being made that he found lacking, along with a rebuttal of each. That apparently did not have the desired effect, as he bowed out of the discussion shortly thereafter:
For some, that may be just as well. Raymond Hettinger said that he was worried that it was not the
right time for a discussion of
PEP 505 as it might introduce "divisiveness when we most need for be
focusing on coming together
". Furthermore, he was not a fan of the
feature for a number of reasons:
This PEP is one step further away from Python reading like executable pseudo-code. That trait is currently a major draw to the language and I don't think it should get tossed away just to mitigate a minor irritant.
He also noted that other implementations of Python are having a hard time
keeping up with the "ferocious rate of change
" in recent
Python releases, so he thinks a moratorium on language changes makes sense.
He listed off a long string of features that have been
added and wondered how many folks—including CPython core developers—were on
top of all of them. "We've been putting major changes in faster than
anyone can keep up with
them. We really need to take a breath.
"
Informally, a moratorium is what the participants in a thread on the python-committers mailing list (where only core developers can post) have more or less recognized. There is a de facto moratorium because of a lack of a way to decide on a PEP, but, even once that logjam has cleared (currently planned to be completed early in 2019), it seems likely that any major changes will push out to Python 3.9 (currently targeted for 2021)—at the very least.
The discussion of PEP 505 may serve another purpose, as well. Discussions of PEPs in python-ideas are supposed to be more freewheeling and potentially fractious, but the scars of PEP 572 linger in many ways. This discussion may fuel the efforts to find other ways to discuss PEPs once they reach the point where they might be decided upon (and would typically then move to the python-dev mailing list). Presumably, discussions on python-ideas would stay the same, but what happens after that might be in for some changes—much like the Python project itself at this point.
Index entries for this article | |
---|---|
Python | None |
Python | Python Enhancement Proposals (PEP)/PEP 505 |
Posted Aug 1, 2018 16:23 UTC (Wed)
by acarno (subscriber, #123476)
[Link]
- StackOverflow's Q/A format
It could tamp down on the sheer number of emails (you could follow specific posts/reply threads) and perhaps limit the amount of bike shedding (presumably comments with more substantial replies get a higher ranking).
No idea if it would work, but I figure it's worth putting the idea out there. I'd love to hear feedback/critiques.
[1] https://redditblog.com/2009/10/15/reddits-new-comment-sor...
Posted Aug 1, 2018 17:16 UTC (Wed)
by quotemstr (subscriber, #45331)
[Link] (3 responses)
Posted Aug 1, 2018 18:09 UTC (Wed)
by rgmoore (✭ supporter ✭, #75)
[Link] (2 responses)
I think any proposal for Python macros is likely to be dismissed out of hand. Look at how much resistance a handful of relatively minor pieces of syntactic sugar have faced. One of the things Python people really love about their language is its simple, consistent syntax. Python has only one standard dialect, so any experienced programmer can read somebody eles's program and understand what it's doing. Allowing anyone to make arbitrary syntax changes blows that up.
Posted Aug 2, 2018 6:47 UTC (Thu)
by brooksmoses (guest, #88422)
[Link]
But you could do it as something like Ratfor, where it's something implemented as a distinct preprocessor rather than part of the language itself. If it caught on about as much as Ratfor did -- which is to say, being handy for exploring language ideas but never really getting widespread use of any sort -- that might be a useful thing to have around.
Posted Aug 6, 2018 0:22 UTC (Mon)
by sionescu (subscriber, #59410)
[Link]
Posted Aug 1, 2018 17:51 UTC (Wed)
by marduk (subscriber, #3831)
[Link] (3 responses)
Posted Aug 1, 2018 21:17 UTC (Wed)
by quietbritishjim (subscriber, #114117)
[Link]
Posted Aug 2, 2018 8:27 UTC (Thu)
by flup (guest, #115570)
[Link]
Posted Aug 2, 2018 20:35 UTC (Thu)
by flussence (guest, #85566)
[Link]
Posted Aug 1, 2018 19:33 UTC (Wed)
by epa (subscriber, #39769)
[Link]
Posted Aug 2, 2018 2:18 UTC (Thu)
by sml (guest, #75391)
[Link] (3 responses)
The raison d'être of python is explicit verbosity AKA executable pseudocode.
If this goes in after PEP572 then the value proposition of Python is significantly lowered because it become more Perl/Rubyish. In that case, why would I use Python for my line-noise scripts over Perl or Ruby?
Posted Aug 2, 2018 5:30 UTC (Thu)
by quotemstr (subscriber, #45331)
[Link] (2 responses)
Posted Aug 2, 2018 20:06 UTC (Thu)
by tartley (subscriber, #96301)
[Link] (1 responses)
Perhaps people who are in favor don't experience this with '?[', etc. Perhaps it's a matter of familiarity of similar features in other languages. Or perhaps it's a genuine distinction between widely intuitive and simplifying syntax versus a needless obfuscation. I'm not trying to be judgemental with that language. I'm positing a genuine question.
I'd love to hear any positions that could genuinely help differentiate, as opposed to just pouring more opinions on the flames.
Posted Aug 3, 2018 16:11 UTC (Fri)
by felixfix (subscriber, #242)
[Link]
I can see advantages of rigid languages for some esoteric cases. Maybe medical devices or nuclear weapon control should be such. But there are always trade-offs -- for every seen characteristic, there are more unseen trade-offs, and Bastiat isn't the only one who wishes more people would see them.
As is almost always the case, flexibility and adaptability win the day. I have no stake in this matter, but that's partly because I dislike the rigid thinking that created this discussion out of thin air.
Posted Aug 2, 2018 10:22 UTC (Thu)
by fagan (guest, #60302)
[Link] (3 responses)
Posted Aug 2, 2018 14:36 UTC (Thu)
by acarno (subscriber, #123476)
[Link] (2 responses)
This strikes me as doublethink (if you'll excuse the Orwellian reference). Sure, the syntax is a quality of life improvement for experienced developers, but if it's non-Pythonic, isn't that reason enough for it *not* to belong in the *Python* language? It seems to cut to the heart of that question: for what purpose was a language written?
A better solution, in my opinion, would be to switch to a language that offers such compact syntax (Perl? I'm not sure, never used it). That requires leaving the Python ecosystem, however, which is of course a non-starter if your entire software stack uses Python. I guess there's not much of a way around that problem unfortunately.
Posted Aug 2, 2018 17:03 UTC (Thu)
by epa (subscriber, #39769)
[Link] (1 responses)
Posted Aug 2, 2018 22:47 UTC (Thu)
by rgmoore (✭ supporter ✭, #75)
[Link]
I don't think that's what's happening. I'm not a Python programmer myself, but I get the impression that a huge part of what makes Python Python- and what makes it popular- is that it has an aesthetic sense of what the language is supposed to be like. Part of that is the idea that it's more important to be clear than to be concise, and something like
Posted Aug 2, 2018 14:46 UTC (Thu)
by felixfix (subscriber, #242)
[Link] (6 responses)
Verbosity is fine for beginners or suits. Once you gain any familiarity with a language, you get tired of "ADD 1 TO EMPLOYEE-PAYROLL-SUM RESULTING IN EMPLOYEE-PAYROLL-SUM" and salivate at those lucky FORTRAN programmers who can fit the entire statement on a single line.
I vaguely remember someone coming up with a COBOL translator which would let you use abbreviations and shortcuts in your source, then convert it to regulation verbosity for compilation. Maybe Pythonistas could do the same, unofficially of course, if verbosity is the official mantra.
You get used to verbosity and shortcuts. It's just familiarity. I suppose Perl programmers think of APL as line noise and APL programmers feel pity for those poor Perl programmers.
It's all programming. I understand purists wanting to preserve what they are used to, but I've programmed in too many different environments with too many different personal styles to have much sympathy for the practicality of static systems. Be flexible or suffocate is my motto. If you can't adjust to variation, if deviations trigger you, if diversity threatens you, then your designs will be equally stagnant and unforgiving.
Posted Aug 2, 2018 16:42 UTC (Thu)
by naptastic (guest, #60139)
[Link] (1 responses)
Posted Aug 2, 2018 17:13 UTC (Thu)
by felixfix (subscriber, #242)
[Link]
Can't remember ever being asked that before. I have no idea how to respond. If it's any help, I am no fan of copyrights, so quote at will, and as for attribution, well, there's a handle already in place.
Heavens to Betsy!
Posted Aug 3, 2018 11:56 UTC (Fri)
by NAR (subscriber, #1313)
[Link] (3 responses)
Posted Aug 3, 2018 15:01 UTC (Fri)
by nybble41 (subscriber, #55106)
[Link] (2 responses)
This isn't a matter of easer of reading vs. ease of writing. *Reading* long operators, variables, function names, etc. is equally cumbersome. People speak derisively of languages whose syntax resembles "line noise", but repeating the same long name or awkward syntax a dozen times in the same function when something shorter would have been just as easy for the target audience to understand is merely another kind of noise.
Posted Aug 3, 2018 16:21 UTC (Fri)
by felixfix (subscriber, #242)
[Link] (1 responses)
It is the same with programs. I know I have been misled more than a few times by long variable and function names that my mind is reluctant to study carefully every time I see it. When a program is full of 20-30 character variables and methods, it bogs me down and makes it harder to understand the code. On the other hand, if I am skimming code for a general understanding, it's not as important. If someone tells me to interface to some method, sometimes the functionality is not clear and I need to read the code to know what it actually does, but I have never seen it before and don't expect to ever see it again. Then longer names may be more useful.
Posted Aug 4, 2018 12:23 UTC (Sat)
by madscientist (subscriber, #16861)
[Link]
Many of the suggestions there are specific to C, and even to C of the late 1980's/early 1990's, but the typography advice is still something I tend to follow today.
Posted Aug 2, 2018 18:21 UTC (Thu)
by jezuch (subscriber, #52988)
[Link] (2 responses)
Posted Aug 3, 2018 8:14 UTC (Fri)
by marcH (subscriber, #57642)
[Link] (1 responses)
Posted Aug 9, 2018 6:49 UTC (Thu)
by HelloWorld (guest, #56129)
[Link]
Posted Aug 2, 2018 19:57 UTC (Thu)
by naptastic (guest, #60139)
[Link]
Add it. Add it now and don't look back.
(Just don't add sigils.)
Posted Aug 3, 2018 8:19 UTC (Fri)
by marcH (subscriber, #57642)
[Link] (2 responses)
So once again, divide and conquer (and maybe don't upset the next BDFL):
- 1st PEP : is the current syntax too long and worth new, unspecified operators?
- Only if the 1st PEP is approved, 2nd PEP: debate the new syntax.
Posted Aug 3, 2018 8:53 UTC (Fri)
by excors (subscriber, #95769)
[Link] (1 responses)
Otherwise it seems a little bit like the politician's syllogism - "PEP 1: We must change the syntax. PEP 2: This is a change to the syntax. Therefore we must implement PEP 2".
Posted Aug 3, 2018 14:02 UTC (Fri)
by marcH (subscriber, #57642)
[Link]
Agreed: I'm not sure how you can erase memories and convince yourself you never saw something :-)
1. Do you find *any* of the newer syntaxes offered better? YES/NO question, binary answer. Look at all propositions but not allowed to bikeshed yet.
Besides focusing the discussions it also lets the (minority of) people who vote "no" choose what they find to be the lesser of all evils if they lost.
If no majority in step 2. then too bad: no new syntax. Now you could have people "gaming the system" and defending unpopular propositions not because they like it but just to make the whole process fail, however I hope most people in this case wouldn't go down that low.
You can further break down 2. into two steps by grouping propositions into "classes" of similar variants, example:
2.1 which pseudo-YACC code do you prefer?
Discussions about syntax/most basic language features are always passionate - hence messy and very unproductive. So anything that can bring some order to them would help.
Posted Aug 3, 2018 9:17 UTC (Fri)
by mb (subscriber, #50428)
[Link] (4 responses)
> if x is None: x = 42
instead of this unreadable !@^%^&#%$
> x = x ?? 42
I don't oppose against adding new operators. Like := for example, which does actually make code more readable and even sometimes perform better by reducing redundancy such as in comprehensions.
Posted Aug 4, 2018 7:27 UTC (Sat)
by epa (subscriber, #39769)
[Link] (3 responses)
x = g()
That can be simplified to
f(g() ?? 42)
avoiding the intermediate variable altogether.
Posted Nov 14, 2021 11:06 UTC (Sun)
by diegor (subscriber, #1967)
[Link] (2 responses)
Posted Nov 14, 2021 13:44 UTC (Sun)
by mathstuf (subscriber, #69389)
[Link] (1 responses)
f(nvl(g(), expensive()))
because the `expensive()` will be called even if `g()` is not `None`.
Posted Nov 14, 2021 21:05 UTC (Sun)
by nybble41 (subscriber, #55106)
[Link]
Like many things, this can be fixed with some indirection:
Posted Aug 7, 2018 21:50 UTC (Tue)
by mirabilos (subscriber, #84359)
[Link] (2 responses)
It’s one of the things C# has, and which I kind of envy, especially in crapuages like Java™.
We need object.anotherobject.yetanotherobject.method() way too often, and just propagating nil as result if one of the chain is nil alone would be a GREAT help, let alone some of the other possibilities described.
Posted Aug 7, 2018 22:21 UTC (Tue)
by Cyberax (✭ supporter ✭, #52523)
[Link] (1 responses)
Posted Aug 8, 2018 0:06 UTC (Wed)
by mirabilos (subscriber, #84359)
[Link]
(It’s also a meta-answer and as such does not contribute to the discussion on the topic itself.)
Posted Aug 10, 2018 23:33 UTC (Fri)
by Pc5Y9sbv (guest, #41328)
[Link]
Having to swap between Python and SQL a lot lately, I sometimes try to imagine having Python None act more like SQL NULL. It can be very convenient to rely on expressions evaluating to None and using COALESCE(expr, ...) to supply fallback expressions to try in order when you don't want a None value. However, the mechanism in SQL is more than just guarding for NULL values. Many valid operator and function-call scenarios will return NULL with NULL inputs: as opposed to raising errors in Python: but, given the different type systems, SQL NULL does not blindly suppress usage errors: It would be quite a different language to introduce typed expressions and typed NULLs like this. But, if Python had gone with something like NullValueException for common error cases above, we could imagine using exception handling to emulate much of the useful NULL handling in SQL. We'd still need new special syntax for coalesce() unless we want to wrap expressions in thunks to delay their execution:
I agree with others above that an operator that only guards literal None values seems silly, when you can already write a conditional expression that directly communicates your intent: The main power of NULL-safe expressions is when the NULL can be encountered in deeply nested functional expressions and captured, much like exception handling lets us selectively abort or intercept imperative call chains.
Adding None-aware operators to Python?
- Hacker News' hidden points
- Reddit's "best" sorting algorithm [1]
Two words: reader macro
Two words: reader macro
Two words: reader macro
Two words: reader macro
Adding None-aware operators to Python?
mangle_from_ = True if policy is None else policy.mangle_from_
mangle_from_ = policy?.mangle_from_ ?? True
As a long-time perl-to-python convert and native English speaker, it's going to be really difficult to convince me that the latter is easier to read than the former. Additionally I don't understand why the latter would be preferred other than it saves 19 characters. It mostly seems cute for the sake of being cute, but in my opinion it's not.
I agree with your point, but the second line is actually equivalent to this, which is admittedly even more verbose:
Adding None-aware operators to Python?
mangle_from_ = (
True if policy is None or policy.mangle_from_ is None
else policy.mangle_from_
)
I think it's no big deal to go ahead and use an if statement here, and I have assumed it suffices to test for truthiness of the structure (I'm guessing that when chaining ?? like this, that's usually going to be fine in all but the last comparison):
if policy and policy.mangle_from_ is not None:
mangle_from_ = policy.mangle_from_
else:
mangle_from_ = True
Adding None-aware operators to Python?
Amusingly, that bottom line is only a few characters off being valid perl6:
Adding None-aware operators to Python?
mangle_from_ := policy.?mangle_from_ // True
…though perhaps not perl code anyone would want to write or read. Something more idiomatic would go like:
with policy {
mangle_from_ := policy.mangle_from_;
…
}
else {
mangle_from_ := True;
# assign other defaults
}
C#
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Isn't it a bit circular to define what is Pythonic in relation to the current version of the Python language?
??=
(or worse foo?.[bar]
) offends that sense of what Python is supposed to be like. I use Perl, so I'm used to constructs like //=
and they don't bother me, but I can certainly understand somebody not wanting that in their language because it goes against what the language is supposed to be like.
Interesting comparison to COBOL
Interesting comparison to COBOL
Interesting comparison to COBOL
Interesting comparison to COBOL
Interesting comparison to COBOL
Interesting comparison to COBOL
When I was a young programmer I read Rob Pike's Notes on Programming in C and it was very influential on me... which is probably to say it aligned with and clarified my natural inclinations.
Interesting comparison to COBOL
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
Adding None-aware operators to Python?
2. If 1. is yes, then discuss and chose one.
2.2 which pseudo-LEX code do you prefer?
Adding None-aware operators to Python?
One of the best things of the Python language is that lots of expressions and even statements can be read as an English sentence.
For that reason the 'and' operator is better than having &&, even if && is less characters to type.
Same goes for ??. We already have syntax to express the exact same thing. Just use that and abandon ??.
Adding None-aware operators to Python?
f(42 if x is None else x)
What about using a function?
Adding None-aware operators to Python?
def nvl(v, default):
if v is None:
return default
else:
return v
f(nvl(g(),42))
Eventually nvl() can be made a standard library function.
Adding None-aware operators to Python?
Adding None-aware operators to Python?
def nvl(v, default):
if v is None:
return default()
else:
return v
f(nvl(g(), lambda: expensive()))
Adding None-aware operators to Python?
Adding None-aware operators to Python?
That's a sign of a bad design, btw. See: https://en.wikipedia.org/wiki/Law_of_Demeter
Adding None-aware operators to Python?
not if you’re working with local/known-to-the-application
nested data structures or somesuch.
Adding None-aware operators to Python?
(NULL::integer) + 5 --> NULL
(NULL::foo_type).id --> NULL # if foo_type has a field id
some_array[NULL::integer] --> NULL
(NULL::integer[])[5] --> NULL
None + 5 raises TypeError
None.id raises AttributeError
some_list[None] raises TypeError
None[5] raises TypeError
None(5) raises TypeError # no equivalent in SQL, since functions are not expressions
NULL::text + 5 raises error # text+integer operator does not exist
(NULL::foo_type).bar raises error # if foo_type does not have field bar
some_array[NULL:text] raises error # text is not a valid subscript
(NULL::integer)[5] raises error # integers do not support array subscripts
def coalesce(*args):
for arg in args:
try:
result = arg()
if result is not None:
return result
except NullValueException:
pass
coalesce(lambda: x[y], lambda: z+2, lambda: 42)
x = x ?? 42
# does each variant below communicate expectations about common case?
x = x if x is not None else x
x = 42 if x is None else x