
PEP 505: Bringing None-Aware Operators to Python - np_tedious
https://www.python.org/dev/peps/pep-0505/
======
Waterluvian
Here's an example the PEP provides:

    
    
        if libpaths is None:
            libpaths = []
        else:
            libpaths =  libpaths.split(":")

After updating:

    
    
        libpaths = libpaths?.split(":") ?? []
    

Python is great for beginners for many reasons, two of which are: code is
obvious when read, and we all write the same way so you can go read expert
code and learn from it. There is so much more to programming and Python than
just optimizing keystrokes and lines of code.

In my opinion, the PEP 505 version is entirely illegible to a reasonable
python beginner. And this hurts the language more than spreading the
instructions across a few extra lines.

I am concerned that PEPs are always written by experts who will, intentionally
or not, bias towards an expert-friendly language.

~~~
mlevental
are python devs the most curmudgeonly/conservative devs in the world? syntax
is never a barrier to legibility of code because code is not meant to be
parsed one character at a time (by programmers). the legibility always comes
down to the semantics and abstraction. in my opinion a conciser ternary has
very clear semantics and therefore is intelligible. I'm also of the opinion
that it's very useful to save on things like `get(get(a, None), None)`

~~~
msl09
I think that a lot of the discussion of python problems is steered by the
infinitely many python book writers and course instructors that have profited
significantly by the current trend of "everyone must learn to code!".

If the recent changes to python syntax were to python educators would be the
most affected ones since they would have to update their material or see it
obsoleted. Of course there's the moral issue that they would have been
misleading students if they were to say that python is as simple as it can be.

Every developer whom I spoke have similar feelings about the changes, they are
minimal and if they use it, very frequent boiler-plate code could be dropped.
These are of course developers that have been working with python for years
and have significant code bases to maintain, novices are likely to feel
otherwise.

~~~
toyg
Your conspiracy theory is mistaken; if anything instructors profit handsomely
by language churn, as people are forced to come back after this or that
update.

No, the problem is simple featuritis spurred by adoption. Python has reached a
point where the language is basically feature-complete, but adoption keeps
growing. That means that more and more programmers arrive to the ecosystem
from other fields, and advocate for constructs they are familiar with or that
map more closely to their problem domains. This influence is a good thing in
some cases, and a bad one in others.

Operators in particular are a minefield. Python is traditionally inclined
_not_ to use special operators, which helps readability quite dramatically.
There are very few exceptions (basically only @ for decorators, which is
outside code flow anyway). This is why people hate new operators so much: we
work with Python to _stay away_ from unreadable, write-only code full of
special characters. I understand the frustration of rote in some areas, and
any professional is free to sharpen his own tools in the way he prefers --
just don't force the ecosystem at large to lower its code quality just so you
can check out 10 minutes earlier from your 9-to-5 large-codebase CRUD job.

------
basicwolf
We have a lot of Django-based code similar to

    
    
      if getattr(obj, 'foreign_obj') is not None and getattr(obj.foreign_obj, 'field_name') is not None:
    

Would this turn into:

    
    
      if obj?.foreign_obj?.field_name
    

?

Does is look shorter? - YES!. Is it more readable? Arguably yes. Would I vote
to see this feature in Python? HELL NO! In most of cases, we can have an in-
house "maybe()" function, like

    
    
      maybe(obj, 'foreign_obj.field_name')
    

There is no need to update the language syntax for that.

From PEP description:

    
    
      From bisect.py:
    
      def insort_right(a, x, lo=0, hi=None):
            # ...
            if hi is None:
                hi = len(a)
            # ...
    
      After updating to use the ??= augmented assignment statement:
    
        def insort_right(a, x, lo=0, hi=None):
            # ...
            hi ??= len(a)
            # ...
    

Seriously? To me the "if hi is None" looks times more readable and easily
comprehensible than "hi ??= len(a)".

Finally, The Zen of Python

    
    
      Special cases aren't special enough to break the rules.
      Although practicality beats purity.
    
    

This case does not look neither special enough nor so much practical to me.
Could anyone please give a hint of where can one vote against this PEP?

~~~
pjz
...why does everyone forget that `getattr()` has an optional `default`
argument? It's helpful for stuff like this.

~~~
Doxin
Same reason people forget min and max have key arguments: You mostly don't
need them until you really do.

------
makecheck
I’ve found that operators boil down to saving time _writing_ (once) at the
expense of later readability. They are also almost impossible to trace if
operators are overloaded. And you have to hope that the overloaded operator
has a meaning consistent with other uses of the operator.

Stop trying to shorten code by 2 lines. It’s not that bad to write it out. If
it helps, think ahead to the 1st or 5th revision of the code you’re about to
write and imagine where you’d even be able to add new code, given magical
operators. In a case like this, it’s easy to imagine a single “else” case with
“?” needing to change into multiple else-if cases, requiring the entire fancy
operator expression to be rewritten. No real saving.

~~~
CurlyJefferson
"Stop trying to shorten code by 2 lines."

Agreed. Python code tends to be concise as is. There's no need to add little
tricks to cut out a line or two at the expense of readability.

Along those lines, in a recent code review a developer balked at some proposed
code and boasted how he could do the same thing in fewer lines. His "improved"
code had a keyword parameter where the default was set to a lambda function
containing nested list comprehensions plus a zip function... I voted against
his "improvement" since it was the most unpythonic thing I'd ever seen. I'll
take added readability and simplicity at the expense of a few extra lines.

~~~
talltimtom
> Agreed. Python code tends to be concise as is. There's no need to add little
> tricks to cut out a line or two at the expense of readability.

I must say I agree fully, and even so, in cases where you really want to cut
down verbose sections or boilerplate, there is so much you can do through
defining your own classes and functions and overloading operators. Even then
there is little need for new fundamental syntax.

------
webmaven
It will be interesting to see how this PEP is handled by the community with
Guido off on a permanent vacation, and the mood among Python core devs
seemingly "no major changes to syntax for the next little while" .

Personally, some of the examples using the new operators are in fact easier to
read, but others border on illegibility, and I don't think the tradeoff is
wise.

Then again, I felt the same way about Python's decorator syntax (ie. @) when
it was proposed, and I still find it jarring.

~~~
toyg
_> It will be interesting to see how this PEP is handled by the community_

It was created three years ago, and it's still just a draft. Hopefully it
won't go anywhere, with or without Guido around.

EDIT: Raymond Hettinger is on the ball as always: _" This PEP also shares some
traits with PEP 572 in that it solves a somewhat minor problem with new syntax
and grammar changes that affect the look and feel of the language in a way
that at least some of us (me for example) find to be repulsive. 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"_

~~~
webmaven
And yet, PEP 572 _was_ recently accepted...

------
G2kyd7
Another +1 for rejection. Python is popular because it is easy to write
idiomatic code that is easy to understand by humans, which I think is one of
the features that separates bad from good code. This proposal would only add
non-intuitive syntax (e.g. extensive operator chaining) that will make code
more complicated to read, even if you are not a beginner, only to save 1-2
lines of code.

------
vinceguidry
Null-awareness is something that, once you start relying on it, you really
start to miss not having it. I think having idiomatic and easy ways to shuffle
nulls out of the system is practically required for any dynamically-typed
language.

You need terse ways to do it because once your codebase reaches that point
where the behavior is sketched out and now you need more correctness, you're
going to be using it _everywhere_ , at least until you've discovered all the
main sources of ambiguity so you can gateway those separately.

I'm a Rubyist, being dragged kicking and screaming into NodeJs world, so I
don't have a dog in this fight, but this kind of thing and the reaction I'm
seeing to it in this article makes me happy with my language choice.

Python seems to be seeking out a middle ground between a structured
programming language and the web world. Which is fine and all, but it seems to
be taking the worst part of both worlds. The verbosity and finickiness of
syntax of structured languages and the performance of dynamic ones.

------
sciurus
Here's a write up of the chilly reception this recently received on the
python-ideas mailing list:
[https://lwn.net/Articles/760993/](https://lwn.net/Articles/760993/)

~~~
toxik
The whole endeavor seems a bit quixotic to me. This kind of change would no
doubt cause such a stir that there’d be a fork before long.

~~~
__s
No, it's not that drastic, especially considering prior art in other languages

Not supporting the change, but let's not be dramatic

~~~
toxik
I'm fairly well attuned to the sensibilities of Pythonistas and between this
and the recent stepping down of the BDFL, it would definitely invite a fork,
fuelled in no small part by the vacuum that exists in spearheading the Python
project.

------
gonational
Please don’t do this, Python!

I agree that the common patterns used for None values can be verbose; but,
they’re readable and clear. PEP 505 syntax looks like Martian.

IMHO, core developers should spend the next two years focusing on performance.

If they can just make cPython 50% faster (avg) and use 25% less memory (avg),
Python can capture so much more marketshare; this increases the value of the
ecosystem and economies of scale therein.

The language itself needs no changes.

------
thijsvandien
I am quite concerned about the kinds of PEPs that come up lately (edit: I now
noticed it's three years old). Python is drifting farther and farther away
from its nature and strength. The amount of complexity is constantly going up
and I don't think it's a good thing. Please let this language be what is is.

A small amount of boilerplate in cases like this is fine and motivates you to
restructure the code rather than hiding the mess in this way.

Why write

    
    
      data = data if data is not None else []
    

as

    
    
      data = data ?? []
    

if you could simply use

    
    
      data = data or []
    

which already exists and for all intents and purposes should achieve the same
thing?

Need to make sure you can always append to something so you can drop some
conditions?

    
    
      lst = get_log_list()
      lst?.append('A log message')
    

would have been

    
    
      lst = get_log_list() or []
      lst.append('A log message')
    

right now. In terms of reconsidering the structure of your code, I wonder if a
log list not existing or being empty is a meaningful distinction. Perhaps it
could return an empty list to begin with.

Even

    
    
      libpaths = libpaths?.split(":") ?? []
    

is fairly easy to deal with already if you absolutely want to it be short:

    
    
      libpaths = (libpaths or '').split(":")
    

Then again, if it is going to be treated as a string, why would it ever be
None rather than an empty string? Is that distinction important? Being able to
shove it under the rug by sprinkling some question marks over it, allows you
to never stop and wonder about that, when in fact, you should.

~~~
emblaegh
> data or [] Unfortunately this kind of conditional assignment does not work
> if `data` is a numpy array. This arguably more numpy's fault than python's,
> though it is a mildly infuriating when it happens.

------
reggieband
null in languages (or None in Python) is one of the few criticisms I hear from
pure-functional minded evangelists that I have come around to. Projects
started by novices tend to start with no null checks at all with lines like:

    
    
        some.object.other.method();
    

Then at some point after months/years of null pointer exceptions you get a
code base littered with:

    
    
        if (some && some.object && some.object.other && some.object.other.method) {
            some.object.other.method();
        }
    

Or variants like assertions / try-catch blocks / etc.

This is even more cumbersome/ugly when needing to assign the result to a
constant:

    
    
       const foo = some && some.method && some.method();
    

I would very much like to do away with null. There is some half-formed idea in
my mind that this problem is related to how we allocate memory and the concept
of the heap. I don't think syntax can solve this issue.

My main issue with syntax like:

    
    
       const foo = some?.object?.other?.method();
    

Is that it encourages sloppy error handling by making the conditional branches
in the code implicit. I don't condone the (a && a.b && a.b.c) pattern so I
don't really want a shorthand for it.

------
shawnz
I'm disappointed to see that everyone hates this PEP. I think null-conditional
operators are pretty self explanatory even to beginners and they have the
potential to remove a lot of boilerplate which actually could improve code
readability in many cases. I wonder if this massively negative response isn't
just a reaction to everyone having been burned by the PEP 572 debacle.

~~~
theelous3
You have been deeply disconnected from beginners if you believe this. I
absolutely assure you, someone new to programming will have no idea what in
the name of god this is, and will struggle with it.

~~~
shawnz
How can you say that with such certainty? Do you have an example of a similar
construct where you've experienced beginners being confused by it, or are you
just dismissing my opinion based on your opinion?

------
mmirate
_sigh_ no, what Python should actually have is a way to compose fallible
computations such that if any one should fail, the entire composition short-
circuits and returns the error; while not needing each one to check its input
for such a case.

It could even be generalized so that it would work properly even for things
other than the _ad hoc_ union-type formed by the billion-dollar mistake...

Why must so many languages incur upon themselves so much trouble by lacking
such a simple thing as the monad abstraction?

~~~
bvrmn
Monad abstraction is a mere crutch to fulfill compiler greed. It is not needed
in dynamically typed langs.

~~~
mmirate
> compiler greed

What good compilers require, they repay hundredsfold in exhaustively
eliminating entire categories of mistakes from every program that compiles
without error.

~~~
bvrmn
> they repay hundredsfold

Most python apps is simple data proxies. Glue dicts from multiple sources into
more complex dicts and pass further. If you will try to do proper modeling
here you never accomplish a task.

~~~
mmirate
On the contrary. A simple data proxy involves not much computation, but mostly
reshaping; what _kind_ of thing you have becomes more important than _what_
thing you have, and eliminating confusion in the former realm is _precisely_
what static-typed code with proper modelling, excels at. And any competent
static-typed language will have enough macro-like capabilities to generate the
model code (along with as much of the boilerplate as possible) from a JSON
Schema or similar.

(Confusion in the latter realm, on the other hand, is one of the most common
sources of remaining bugs once typing errors and other footguns are
eliminated-with-prejudice.)

~~~
bvrmn
If you will do proper modeling in each intermidiate processing unit you never
accomplish a task. It is software design 101. We check invariants on the
endpoints not in the middle.

------
jnwatson
Like many UI features, it is hard to get a feel for this without trying it.

Swift uses this syntax and I got quite used to reading and writing it.

I’m all in favor of it.

------
freyr
I've always thought Python was a little too readable and obvious. I'm glad
people are hard at work trying to fix that.

------
Dowwie
This sort of functionality is at odds with the Zen of Python. It's not
intuitive at all.

------
bvrmn
Very strange PEP. Most `??` cases can be covered with simple `or`.

~~~
UncleEntity
Not necessarily...

    
    
      x = 0
      y = (x or 42)
    

isn't the same as

    
    
      x = None
      y = (x or 42)

~~~
bvrmn
Yes, it isn't the same in a generic sense. But can be applied in many
practical cases.

------
tosser
On small trick that Pythonistas hate:

    
    
        x = x if None else x
    

Saves a ton of CPU time and is beautiful.

~~~
kjeetgill
Huh, what's that do? It seems to assign x = x which is reminiscent of my pet
"ugly" optimization: adding x = x to the top of a nested scope. It binds the x
from a global scope to x in a local one. Local variable lookup can be
substantialy faster given a hot enough loop.

