|
|
Subscribe / Log in / New account

Not coalescing around None-aware

By Jake Edge
December 22, 2022

The wish for a "None-aware" operator (or operators) is longstanding within the Python community. While there is fairly widespread interest in more easily handling situations where a value needs to be tested for being None before being further processed, there is much less agreement on how to "spell" such an operator (or construct) and on whether the language truly needs it. But the idea never seems to go away, with long discussions erupting every year or two—and no resolution really in sight.

PEP 505

We looked at the idea back in 2018, but PEP 505 ("None-aware operators") goes back to 2015; it seems likely that the idea had been discussed well before that as well. At the time of our article, the Python community was still working on figuring out how it would be governed after Guido van Rossum stepped down from his benevolent dictator role. PEPs were not being accepted or rejected because of that and PEP 505 was deferred.

In Python, it is not uncommon to see code like the following (taken from the more extensive examples in our earlier article):

    if x is None:
        x = 42
The PEP proposes the "??" None-aware (also known as null-coalescing) operator. It returns the left-hand side if it is not None, otherwise the right-hand side is evaluated and returned. So that code above could be replaced with:
    x = x ?? 42
There is also an "augmented assignment" version ("??=") and two operators that apply the None-awareness to indexing ("?[]") and to attribute access ("?.") proposed as well:
    x ??= 42   # same as above
    x?['foo']  # retrieve dict entry 'foo' if x is not None
    x?.foo     # retrieve attribute foo if x is not None
In the last two examples above, if x is None, then the expression evaluates to None as well.

The PEP has come up again a few times since the Python governance upheaval put it on the back burner, including in a Python discussion-forum thread back in April 2021. Kumar Aditya asked about adding a null-coalescing operator; Steven D'Aprano pointed to the PEP and some of the previous discussions. Along the way, PEP co-author Steve Dower said that his plan for the PEP is to drop it "because I now think the additional syntax would not make Python cleaner or a better language".

The PEP came up again in October 2021 when Doug Swarin raised it on the python-dev mailing list. As with Aditya and others, Swarin pointed to the existence of similar operators in other languages (such as JavaScript) and said that it would "result in a significant reduction in boilerplate code" testing for None. He suggested that the indexing ("maybe subscript") and attribute-access ("maybe dot") operators might actually lead to a decrease in code readability, so perhaps they could be removed from the PEP, though he was not personally in favor of doing so. He had also created a pure-Python implementation that he made available for testing.

Van Rossum, who has generally had a favorable inclination toward the PEP all along, thanked Swarin and said that he hoped more discussion would "help convince the Steering Council to accept it". The conversation proceeded along familiar lines, with some strongly advocating for at least the addition of ?? and ??=, while others were expressing concerns about the readability. The specter of "Perl-ification" was present as well; to some, adding more operators of this sort just makes the language look like Perl (or, worse still, line noise).

Revival

On December 11, "yingshaoxo" revived the forum thread that started 18 months earlier and the discussion was off and running again. Yingshaoxo advocated adopting the feature, while noting that multiple languages (JavaScript, Flutter, Kotlin, and C#) already have it. Cameron Simpson noted that there is an existing way to handle the example yingshaoxo posted, but that it does not work in all cases:

    # proposed new syntax
    new_variable = a_variable ?? 'Hello Python'

    # "same" thing with existing syntax
    new_variable = a_variable or 'Hello Python'
That relies on a_variable evaluating to a false value, which is the case for None, but it is also the case for the empty string, 0, and a few other values. D'Aprano pointed out that the same argument was made to resist adding a ternary operator to the language, until PEP 308 ("Conditional Expressions") was abruptly adopted because of the problems that can occur with expressions that unexpectedly evaluate to false:
For many, many years we rejected every request for a ternary if operator with the argument that you can just write
    condition and if_true_value or if_false_value
E.g. len(mylist) > 0 and mylist[0] or "default". Can you see the bug? (Hint: what if the value of mylist[0] is, say, the empty string?).

What followed was a long discussion on "readability". "Fancidev" asserted that the conditional version was more readable:

"y if x is None else x" is more readable than "x ?? y".

Since code is written once and read 100 times, it's probably worth the extra typing.

As might be guessed, others disagreed. Tzu-ping Chung said that the conditional form "requires more mental attention", but did recognize that there is a potential hurdle in needing to learn what ?? means. D'Aprano said that those coming to Python from other languages often complain that the conditional construct in Python is unreadable. "So maybe readability depends on what you are used to."

Fancidev pointed out that ?? can only be applied to a subset of the situations where the more general conditional expression can be used; it requires learning about the operator but can then only be applied to None tests. "Vladimir" agreed, but linked to a section of PEP 505 that argues for ?? because it is more concise. The PEP has an example of initializing default values:

    data = [] if data is None else data

    # or

    data = data if data is not None else []
Either of those will work, but the first puts the operands in an "unintuitive order", while the second is a bit longer and repetitive (i.e. "data if data"). Using the proposed operator, it would simply be:
    data = data ?? []
To Fancidev, those examples just reinforce their belief that the conditional version is more readable, but Chris Angelico argued that "readability" is totally subjective, at least as it is used in discussions like these:
I personally suspect that some people consider something "readable" on the basis that "I can understand what it does based on my pre-existing knowledge of what Python can already do" (meaning that new syntax is ALWAYS less 'readable' than a verbose form that already exists), and other people consider something "readable" on the basis that it is compact and expresses a thought that can be fit into a larger "sentence" or "paragraph" (meaning that a new syntax is almost always more 'readable' than the more-verbose form that already exists).

Coalesce

Marc-André Lemburg took a different tack on the idea. He pointed to the PostgreSQL COALESCE() function as a possible model for "an explicit and elegant way" to solve many of the problems that PEP 505 describes. He suggested adding a Python builtin along the following lines:

coalesce(*args, /, check=None, logic=False)
Return the first value from args which is not the check object (defaults to None). If check is a callable, return the first value from args which check(value) is False. logic may be set to True, to swap the test logic.

The "/" in the argument list separates the positional-only parameters (args in this case) from those that can be specified by position or keyword (check and logic). He goes on to list a few operators as possibilities for the check values, such as a new list.isempty() or the existing math.isnan().

But there is a problem with that approach, as several people pointed out: there is no ability to short-circuit the evaluation of some of the arguments. Using a conditional expression (or the proposed ?? operator) would not evaluate the "else" argument if the value is not None. As Fancidev put it: "it does not lazily evaluate the arguments, which I imagine will be a necessary requirement". Peter Suter added some other ways where the operator approach is superior, including:

Chaining is much clearer and less error prone with operators:
(override ?? fallback).name ?? default
coalesce(coalesce(override, fallback).name, default)

Meanwhile, the "debate" over readability continued, much of it between Angelico and Vladimir, seemingly without changing any minds. In fact, early on in that part of the discussion, Angelico hit the nail on the head. In a message linked above, he decried the idea of "readability" because: "Everyone has their own definition, never backed by any sort of actual studies, and nobody ever changes their mind based on other people's examples." Eventually, after a good bit of back and forth on readability, the thread was locked on December 17.

As should be clear, though, it is a topic that comes up often; until the PEP is either accepted or rejected, it will undoubtedly come up again. Even if the PEP is rejected, it will not be a huge surprise to see the idea pop up again; it has obvious utility and other languages have something similar, which will make it that much more desirable. The arguments against the simplest form (just ?? and ??=) seem to mostly boil down to being a barrier to learning or understanding the language. But, as D'Aprano put it, Python has features for both casual and more serious programmers:

The beauty of Python is that it is accessible to casual programmers. You don't have to use null-coalescing operators any more than you have to write classes, or use closures, or use threads.

But we didn't let those casual programmers stand in the way of Python getting classes, closures, threads, async, regexes etc. Let the casual programmers continue to write using the basic features, and the power users use the power features.

It is hard to predict what will happen from here, especially given that the PEP's authors are no longer pushing it; it seems likely that some other core developer(s) would need to sponsor it for the newly elected steering council to even consider it. If that happens, perhaps an alternate spelling can be found to reduce the unhappiness with the "ugliness" of ??. A reduction in scope (eliminating ?. and ?[]) might also help the prospects of the PEP; down the road those additions could be considered again. One way or another, getting PEP 505 out of limbo would help clarify things quite a bit.


Index entries for this article
PythonNone
PythonPython Enhancement Proposals (PEP)/PEP 505


to post comments

Not coalescing around None-aware

Posted Dec 22, 2022 20:25 UTC (Thu) by developer122 (guest, #152928) [Link] (7 responses)

It would be nice if this thing working with None had a keyword in it that referenced the fact it was working with None. Rather than some arcane "??" symbol, something closer to "eq" or "ne" etc.

It wouldn't even have to literally be the word none necessarily, just something slightly more descriptive to hint in the right direction.

Not coalescing around None-aware

Posted Dec 22, 2022 21:46 UTC (Thu) by smurf (subscriber, #17840) [Link] (6 responses)

Two-letter operators like "eq" and "ne" stink of Perl and should IMHO stay there.

Not coalescing around None-aware

Posted Dec 22, 2022 22:32 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

And if you "negate" them, `-eq` and `-ne` reek of shell ;) .

Not coalescing around None-aware

Posted Dec 23, 2022 8:11 UTC (Fri) by Wol (subscriber, #4433) [Link] (3 responses)

> Two-letter operators like "eq" and "ne" stink of Perl and should IMHO stay there.

They long pre-date Perl.

I've ALWAYS used them (where available) in preference to "=" or "==" or "!=" or "<>".

The trouble with "=" and "==" is they are ambiguous - they stink of *assignment*. How many bugs do you get in C because people accidentally use "assign" when they meant "compare"?

I've used EQ and NE for over 40 years, and they were in use maybe 20 (or more) years before that!

Cheers,
Wol

Not coalescing around None-aware

Posted Dec 23, 2022 9:33 UTC (Fri) by smurf (subscriber, #17840) [Link] (2 responses)

> They long pre-date Perl.

One doesn't exclude the other.

> The trouble with "=" and "==" is they are ambiguous

are they? "=" is assignment and "==" is comparison. This holds for so many languages that by now the confusion is on the side of those who _don't_ do things this way, IMHO.

> How many bugs do you get in C because people accidentally use "assign" when they meant "compare"?

None, nowadays, because compilers warn about assignments in expressions.

Not coalescing around None-aware

Posted Dec 23, 2022 10:00 UTC (Fri) by Wol (subscriber, #4433) [Link] (1 responses)

> > They long pre-date Perl.

> One doesn't exclude the other.

I notice you cut the line before that, which means your comment now doesn't make sense. EQ and NE were *borrowed* from elsewhere. For the OP maybe they stink of Perl. For myself (and presumably many others) I'm not that familiar with Perl but I'm very familiar with EQ and NE. How does that "stink of Perl"?

> > The trouble with "=" and "==" is they are ambiguous

> are they? "=" is assignment and "==" is comparison. This holds for so many languages that by now the confusion is on the side of those who _don't_ do things this way, IMHO.

Okay, so now EVERY language has to do things the C way? What are you going to do about languages where "==" means something other than equality? (just because I can't think of any doesn't mean there aren't any!) Or languages where "=" is context sensitive and could mean either (I use languages like that all the time - one reason I prefer EQ and NE!!!) (I can't remember, I don't believe FORTRAN used "=" for equality ...)

> > How many bugs do you get in C because people accidentally use "assign" when they meant "compare"?

> None, nowadays, because compilers warn about assignments in expressions.

So you get the opposite - where a naive programmer "corrects" the warning, only to discover that the original programmer *intentionally* put an assignment in an if statement ... (I guess "if (result = function()) {" is not uncommon?)

Murphy's law - if your language syntax contains land mines, then at some point you WILL get blown up. And all the defensive programming in the world won't save you, when some newbie comes in, misunderstands it, and treads on the land mine.

Cheers,
Wol

Not coalescing around None-aware

Posted Dec 24, 2022 19:51 UTC (Sat) by NYKevin (subscriber, #129325) [Link]

> What are you going to do about languages where "==" means something other than equality? (just because I can't think of any doesn't mean there aren't any!)

Javascript uses == to mean "loose" equality, which tries to coerce the types of the LHS and the RHS to match before comparing them. Consequently, it is intransitive and can be very unpredictable in certain contexts. They spell true or "strict" equality as ===. The == operator is not (typically) used in modern Javascript, so this is mostly just a quirk of spelling.

= is still assignment, however.

Not coalescing around None-aware

Posted Jan 5, 2023 15:45 UTC (Thu) by azz (subscriber, #371) [Link]

That'd be FORTRAN IV, released in 1962...

Not coalescing around None-aware

Posted Dec 22, 2022 21:44 UTC (Thu) by jbills (subscriber, #161176) [Link] (3 responses)

It is clear that Python just needs to become Haskell with full monad support. (/s)

Not coalescing around None-aware

Posted Dec 23, 2022 8:46 UTC (Fri) by amarao (guest, #87073) [Link] (2 responses)

Current buzz no longer hail monads as pinnacle of CS. Static typing of side effects in a new king. Effects handlers? Ocaml just got them. Should Python follow the buzz?

Not coalescing around None-aware

Posted Dec 26, 2022 23:11 UTC (Mon) by mathstuf (subscriber, #69389) [Link] (1 responses)

> Should Python follow the buzz?

Only if it wants to fizz out :) .

Not coalescing around None-aware

Posted Dec 30, 2022 17:30 UTC (Fri) by ssmith32 (subscriber, #72404) [Link]

Python is old enough now, that even if it just gets a small buzz, there will probably be a hangover later.. ;)

Not coalescing around None-aware

Posted Dec 22, 2022 21:45 UTC (Thu) by smurf (subscriber, #17840) [Link] (15 responses)

> Using the proposed operator, it would simply be:
>
> data = data ?? []

Or, even shorter, it could (probably should, in this case) be

data ??= []

Frankly while I'm no fan whatsoever of Perl-ifying Python syntax, but I'm even less a fan of the various "if None" dances that it'd replace, so ?? and ??= would be a net win IMHO.

I'm not so sure about the others, though.

Not coalescing around None-aware

Posted Dec 23, 2022 11:07 UTC (Fri) by adobriyan (subscriber, #30858) [Link] (14 responses)

It is time to unleash the power of Unicode onto unsuspecting public:

a ≟ []

Not coalescing around None-aware

Posted Dec 23, 2022 12:01 UTC (Fri) by smurf (subscriber, #17840) [Link] (8 responses)

Well, before we go down the road of encoding fancy new meanings with Unicode, maybe aliases for existing features, like ≠ and ≥ and ≔ and ⩵ and of course math.π, should be added to the language … thus the question of ambiguity of = would become moot too, just use ⇐ for assignment. 😎

How to add all of these to your keyboard is left as an exercise to the reader.

Not coalescing around None-aware

Posted Dec 23, 2022 12:04 UTC (Fri) by adobriyan (subscriber, #30858) [Link] (4 responses)

IDEs could convert "=?" to "≟". They do autocompletion all the time.

Not coalescing around None-aware

Posted Dec 23, 2022 12:09 UTC (Fri) by Wol (subscriber, #4433) [Link] (2 responses)

Now you're expecting all programmers to use IDEs...

(As a dinosaur, my favourite IDE is a sheet of a4 :-)

Cheers,
Wol

Not coalescing around None-aware

Posted Dec 23, 2022 13:11 UTC (Fri) by jem (subscriber, #24231) [Link] (1 responses)

Well, then you should have no problem with mathematical symbols like ≤, ≥, and ≠. You are also avoiding the question of tabs vs. spaces, newline representation, and whether your program should end with a newline.

Not coalescing around None-aware

Posted Dec 23, 2022 18:06 UTC (Fri) by Wol (subscriber, #4433) [Link]

:-)

My first boss actually spent his first six months at the company without a computer, so he had no choice BUT to use A4.

(When typed in to the shiny new (actually, second hand) computer, when it arrived, his programs apparently compiled and ran without error ...)

Cheers,
Wol

Not coalescing around None-aware

Posted Dec 30, 2022 20:54 UTC (Fri) by salimma (subscriber, #34460) [Link]

No need for an IDE, even, just a terminal / graphical framework that supports font ligatures and a programmer-oriented font like Fira Code.

Not coalescing around None-aware

Posted Dec 23, 2022 21:02 UTC (Fri) by NYKevin (subscriber, #129325) [Link]

> thus the question of ambiguity of = would become moot too, just use ⇐ for assignment. 😎

R already uses <- for assignment. For symmetry, it also has -> which lets you write a backwards assignment. Somehow, I don't see any other languages adopting this as a standard (even ignoring the fact that C and C++ already have a different -> operator).🙃

Not coalescing around None-aware

Posted Dec 25, 2022 22:34 UTC (Sun) by mtaht (subscriber, #11087) [Link] (1 responses)

I got plenty of function keys left, and an APL keyboard still in storage. Bring it on!

I'm not kidding btw. I'd really like it if more code looked like the math, and an IDE would make it as easy as α, β, Γ. The Δ between well known symbols and their overly verbose english equivalents would increase visual density.

Not coalescing around None-aware

Posted Jan 15, 2023 18:08 UTC (Sun) by sammythesnake (guest, #17693) [Link]

You'd probably like Julia [0], then, it allows Unicode in identifiers and lets you do things like

> for x ∈ Y

(which you can also spell "for x in Y" if you prefer)

and groks "≠" & "≥" as alternate spellings of "!=" & ">=" and so on. ("🫖≠☕" might be perfectly valid code :-P)

The REPL, Jupyter notebooks, and IDEs with support all expand LaTeX escapes for you (e.g. "\in[tab]" becomes "∈" and similarly for all the fun Greek letters / logic symbols / alchemical symbols / emojis etc.) so you don't need a fancy million-key keyboard :-D (Or you can map right-Alt to the compose key if you like)

Personally, I don't have a mathematics background and find many of these symbols somewhat opaque - it doesn't help that they're difficult to Google (but then so are all the punctuation marks that get so much use in programming language syntax!)

It's also an interesting language in its own right that I'm toying around with...

[0] https://julialang.org/

Not coalescing around None-aware

Posted Dec 23, 2022 20:59 UTC (Fri) by LtWorf (subscriber, #124958) [Link] (4 responses)

I always loved how in haskell you can define new operators (a function that sits between 2 parameters, rather than having the parameters after) and could use a wide range of unicode symbols as identifiers.

Not coalescing around None-aware

Posted Dec 26, 2022 3:09 UTC (Mon) by anselm (subscriber, #2796) [Link] (3 responses)

In Python 3, there's nothing preventing you from saying

$ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> π = 3.1415
>>> print(π)
3.1415

Not coalescing around None-aware

Posted Dec 26, 2022 10:36 UTC (Mon) by smurf (subscriber, #17840) [Link]

Well, if you want to do that, please use "from math import pi as π".

Not coalescing around None-aware

Posted Dec 27, 2022 0:20 UTC (Tue) by LtWorf (subscriber, #124958) [Link] (1 responses)

Yes but I can't do

if x ∈ X ∨ y ≤ z: ...

Not coalescing around None-aware

Posted Dec 27, 2022 10:08 UTC (Tue) by smurf (subscriber, #17840) [Link]

If you can write a syntax module that translates ?? into if-None-else conditionals (and which you apparently can do; see the PEP), then writing one that replaces ∈ with "in " and ≤ with "<=" should be child's play.

Not coalescing around None-aware

Posted Dec 22, 2022 21:54 UTC (Thu) by Nahor (subscriber, #51583) [Link] (6 responses)

I found that "readable" is actually two things: "expressiveness" and "compactness".
The first is about how easy it is to understand what an expression means/does, how much other knowledge is needed (language, construct, API, ...).
The second is how much time I need to parse the expression in my head.

"data = [] if data is None else data" is expressive, but it's not compact.
"data = data ?? []" is compact but not expressive.

The two are mostly mutually exclusive so "readability" is about finding the right balance, and is very subjective.

Personally for what it's worth, and as a non-python user, I find the later more readable overall (dependent on how many other similar shortcuts exist which could cause confusion, e.g. I remember Perl being very compact to the point of obfuscation rather than readability :p ).

Not coalescing around None-aware

Posted Dec 23, 2022 6:22 UTC (Fri) by zorro (subscriber, #45643) [Link] (5 responses)

The problem with the verbose construct is that it will be verbose forever. The initially non-expressive ?? construct, on the other hand, will become more expressive as you get used to it.

Not coalescing around None-aware

Posted Dec 23, 2022 10:42 UTC (Fri) by mb (subscriber, #50428) [Link] (4 responses)

> The problem with the verbose construct is that it will be verbose forever.

I don't agree with that.

There are many patterns in programs and languages that a reader doesn't literally read and parse any more after getting used to it. And that pattern matching doesn't really depend a lot on the verboseness of the code.

Take for example a basic iteration loop in C:

for (int i = 0; i < length; i++)

Nobody (with experience) reads and parses that step by step.
It's immediately clear to the reader that this is probably iterating over an array of some kind and i is the index.

The same thing happens with

data if data is not None else default

The big advantage of the verbose form is that you can *also* read and understand it, if you don't know the pattern. You can't do that with special syntax like ??.
Special syntax always increases the mental load and increases the initial learning effort. (Saying that people don't have to lean ?? is also wrong, because other people will use it in their code and examples that Newbies will read).

Not coalescing around None-aware

Posted Dec 24, 2022 13:30 UTC (Sat) by kid_meier (subscriber, #93987) [Link] (1 responses)

But the flipside of assume-the-idiom-without-fully-reading is that it's easy to miss slight deviations from the pattern. When that happens it can often take quite awhile to spot the difference because once our pattern matching machinery is fooled, it can take quite awhile to "unmatch" it.

I also don't think it's fair to say that special syntax always increases mental load. Your pattern matching machinery will work on the special syntax just as well as it works on the fully spelled out syntax--actually quite possibly better since there is less risk of false positives. As someone who writes Java for a living, I think it'd be a good trade. Java already has ternary operator but I'd still welcome a more specialized operator like this.

Not coalescing around None-aware

Posted Jan 5, 2023 15:33 UTC (Thu) by kpfleming (subscriber, #23250) [Link]

You read my mind :-)

The example in the post you referred to may be the 'normal form', but remove the 'not' from it and the meaning changes significantly but a 'quick read' to look for patterns might overlook the change. I can't imagine an actual use for that expression, but I'd hate to misunderstand it because my brain assumed it was just the same as all the others it had seen.

Not coalescing around None-aware

Posted Dec 25, 2022 6:21 UTC (Sun) by Nahor (subscriber, #51583) [Link] (1 responses)

> There are many patterns in programs and languages that a reader doesn't literally read and parse any more after getting used to it.

You're mixing cause and effect.
"verbosity" is not about "how easy it is to read something", it's about the number of tokens/words needed to say something.
Then based on your familiarity with a given expression, the verbosity will have a varying impact on your parsing/understanding speed.

Note though that it will never be as fast as the "??" operator. In big part because you need to check that the words are what you expect them to be (Is the "data" after the "if" really "data" or is it "date" or "dota"? Is the "None" really "None" or is it "Note" or "Noon"? ...). Because of the more limited scope of "??", some of those questions just become irrelevant / have a single and necessary answer.

And that familiarity goes hand in hand with Zorro's comment. The "??" operator, while initially not expressive, will become more expressive as you get familiar with that construct.
Familiarity will make things more readable in all cases, either by making things appear more compact/less verbose by skipping some parts, or by making them more expressive as it gets more ingrained.

> The big advantage of the verbose form is that you can *also* read and understand it, if you don't know the pattern

And we are back to "compact" vs "expressive". One is expressive but verbose, the other is compact but less expressive. One is more readable for newbies, the other for veterans. And people don't agree where the balance point should be.

> Saying that people don't have to [learn] ?? is also wrong, because other people will use it in their code and examples that Newbies will read

Nobody said anything like that. Everybody has to learn. Even the long expression needs to be learned for that matter, because it's not common to have the true-statement on the left of the "if", or that statement that returns a value ("else default") (*). The amount of learning effort is not the same, but it's still there in both case.

(*) more specifically, in most languages, "if" is a statement, which cannot have a value, while here in python, the "if" is an expression, which do have one.

Not coalescing around None-aware

Posted Dec 28, 2022 15:14 UTC (Wed) by marcH (subscriber, #57642) [Link]

> The "??" operator, while initially not expressive, will become more expressive as you get familiar with that construct.
> Familiarity will make things more readable in all cases,...

Except for people who have to make a small change to a Python script rarely, only a couple times a months. I have and always had teammates in that case and that's where Python really shines compares to shell scripts or Perl or others. While the verbose " if None" variations annoy me every time, I totally understand the "Perlification" fear of "??".

Isn't there some middle ground alternative?

Not coalescing around None-aware

Posted Dec 22, 2022 22:00 UTC (Thu) by andrewsh (subscriber, #71043) [Link] (2 responses)

On the contrary, ?. and ?[] would be useful and self-evident additions, while ?? isn't obvious or beautiful.

Not coalescing around None-aware

Posted Dec 22, 2022 23:56 UTC (Thu) by NYKevin (subscriber, #129325) [Link]

In Haskell, the equivalent of those operators is Bind (over the Maybe monad), and it works reasonably well there. Thing is, idiomatic Python doesn't really tend to look like idiomatic Haskell. In Python, if an argument is Optional (i.e. could be None), the first thing you do is check for None and replace it with some default value (or do an early return, raise an exception, etc.). Replacing this style of coding with None-aware operators makes it much harder to visually inspect code and verify that it correctly handles None (one if block vs. every single use of a variable throughout the entire function). If you accidentally do one None-naive operation, the whole thing crashes on the spot.

There are at least two ways to fix that:

* Use static type checking and the Optional type annotation. This requires third-party tools, as CPython does not check type annotations.
* Have unit tests which pass None. This requires additional work, since you need to cover all possible code paths.

The fundamental problem you are going to run into is that Python is a dynamic language, which has had some static niceties bolted on after the fact. There are still people who want to use it as a dynamic language, and telling them "well, just don't use the parts of the language which are hard to read under dynamic typing" is not very nice.

Not coalescing around None-aware

Posted Jan 5, 2023 23:08 UTC (Thu) by flussence (guest, #85566) [Link]

".?" would be yet more self-evident than "?.", because it reuses the existing PCRE "none or one" construct.

Anyway it's a bit absurd to reject these proposals on the basis of "too Perlish". Being like Perl would entail doing almost nothing for 20 years and then devolving into bikeshedding chaos in a rushed attempt to catch up with languages that left them behind.

Not coalescing around None-aware

Posted Dec 23, 2022 0:14 UTC (Fri) by shironeko (subscriber, #159952) [Link] (5 responses)

The existing construct
if x is None:
x = 42
is already pretty readable and concise, and the only problem people seem to have with it is that it is required "too often" right?
So IMO it could be solved by looking at all the situations where this is required and improve the language so the most common use-case for checking for None isn't even needed. In fact python already have things that do this optimization, imagine how annoying this None check problem would be if python didn't have foo(arg=Default) for optional arguments. So introducing similar features could eliminate this None problem and probably do more good to readability than any possible operator name people can think of.

Not coalescing around None-aware

Posted Dec 23, 2022 9:17 UTC (Fri) by ceplm (subscriber, #41334) [Link] (2 responses)

My problem with these operators (and a lot of what already happened to Python in the last few releases) is that it is similar to the Java discussion on the checked exceptions: it is completely dominated by people who didn’t understand the problem and they are trying to get rid of something which they consider just an annoyance.

For me all those if foo is None are code smell: a sign of poorly created API (perhaps unavoidable, because introduced from an external library). Similarly to the checked exceptions, when you start to look for improved syntax which would get rid of if is None then reconsider whole code around the problem and you may find that you need restructure it to express your algorithm better.

Not coalescing around None-aware

Posted Dec 23, 2022 11:05 UTC (Fri) by adobriyan (subscriber, #30858) [Link] (1 responses)

There is Python gotcha where default class member values are global:

class X:
l = []

x1 = X()
x2 = X()
print(x1.l, x2.l)
x1.l.append(1)
print(x1.l, x2.l)

results in

[] []
[1] [1]

so passing None as default value in constructor is obvious solution. I'm not sure how often this is seen in practice but not code smell for sure.

Not coalescing around None-aware

Posted Dec 23, 2022 11:49 UTC (Fri) by smurf (subscriber, #17840) [Link]

> not code smell for sure

Well, "language smell" then – as there really should be a way to instantiate the default option(s) at the time they are needed, not when the "def" statement is compiled.

Attempts to add a way to do this to Python have not succeeded so far.

Not coalescing around None-aware

Posted Dec 23, 2022 20:15 UTC (Fri) by iabervon (subscriber, #722) [Link] (1 responses)

I think this particular example comes from a language design anti-pattern, where, in order to introduce a feature, you present the simplest case in which you could use it. It seems like an easy way to show what the feature can do, but changing the language is not worthwhile just to make a simple statement slightly simpler. There's a value in not repeating an expression, but it's hard to appreciate if the example expression is a single-character variable name.

Consider: "if we're told to check size limits, and the size of the message's header, if any, plus the size of the message's body, if any, is greater than the limit, raise an exception". (And the message representation might be using complicated objects for header and body that may be expensive to get the length of if it isn't needed, and want to clearly distinguish the case of not having a body or header in other places by using None to represent this situation.) That's:

if check_size_limits and (len(message.header ?? "") +
                          len(message.body ?? "")) > limit:
    raise Exception()

With the feature, and:

if check_size_limits:
    header_length = 0
    if message.header is not None:
        header_length = len(message.header)
    body_length = 0
    if message.body is not None:
        body_length = len(message.body)
    if header_length + body_length > limit:
        raise Exception()

Or:

if check_size_limits and ((len(message.header) if message.header is not None else 0) +
                          (len(message.body) if message.body is not None else 0)) > limit:
    raise Exception()

With the feature, you can write something much closer to the specification, and if the next version of the code has to add "likewise for the message's footer", the programmer who copies the "header" section and changes "header" to "footer" can't miss the second place that "header" appeared. Furthermore, the first one consists entirely of text you'd want to read in order to understand what it's doing, while the others have portions you'd skim, and hope that they correctly implement "if necessary". Similarly, "(some long but descriptive expression)?.attribute" is much easier to understand than "(some long but descriptive expression).attribute if (probably the same thing but maybe not) is not None else None", while "x.y if x is not None else None" isn't worth the trouble.

That said, I find the operator "??" doesn't feel Pythonic to me, and I think some short word would fit the Python better, but I can't think of a word that would suit; "?." also seems weird, but I can't think how to avoid using a weird symbol when the basic expression uses as operator already.

Not coalescing around None-aware

Posted Dec 23, 2022 20:48 UTC (Fri) by shironeko (subscriber, #159952) [Link]

How about just have message return it's proper serialized length, maybe with caching so the length check is efficient everywhere you need it and you avoid having to leak the header body footer logic to every call site which will get hard to maintain fast.

Not coalescing around None-aware

Posted Dec 23, 2022 9:41 UTC (Fri) by grawity (subscriber, #80596) [Link]

Chaining is much clearer and less error prone with operators:

(override ?? fallback).name ?? default
coalesce(coalesce(override, fallback).name, default

This reminds me so much of the examples in the "matrix multiplication operator" PEP, just with @ and dot() instead. (It got accepted.)

Not coalescing around None-aware

Posted Dec 23, 2022 10:34 UTC (Fri) by rrolls (subscriber, #151126) [Link] (14 responses)

Personally, I'd like to see PEP 505 implemented almost exactly as presented.

I don't buy the arguments that "x ?? y" or "x ??= y" or "x?.y" or "x?[y]" "is unreadable", and I'd make plenty of use of all four of them - but it sounds like that's already been covered by the whole, "Everyone has their own definition... and nobody ever changes their mind" thing. (On the subject of readability, I avoid ever using the ternary "y if x else z" construction in my code, because I find _that_ unreadable: I've always maintained it ought to be written "if x then y else z", so I'll always write it out with a four-line if-else block instead.)

The one thing that doesn't make sense to me is the choice of precedence for the ?? operator such that:

> (a ?? 2 ** b ?? 3) == a ?? (2 ** (b ?? 3))

The explanation given for ?? to bind "more tightly than other binary operators" makes sense: one would hardly ever expect "x + y" (and the like) to return None, so "x + y ?? z" makes no sense as "(x + y) ?? z" but makes perfect sense as "x + (y ?? z)". So I'm surprised this logic wasn't applied consistently, making "a ?? 2 ** b ?? 3" equivalent to "(a ?? 2) ** (b ?? 3)", which is a valid non-None value whether a and/or b are None or not.

In particular, the PEP claims "parenthesizing the sub-expressions any other way would result in TypeError"... which, unless I'm missing something fundamental, is clearly false as I've just demonstrated by giving such an alternative parenthesization.

Not coalescing around None-aware

Posted Dec 23, 2022 10:51 UTC (Fri) by mb (subscriber, #50428) [Link] (8 responses)

> (a ?? 2 ** b ?? 3) == a ?? (2 ** (b ?? 3))

Holy mother of god.
That's a perfect example of why we shouldn't have this operator.
Seriously. Why don't you simply resolve the None-defaults before doing the calculation?
Even with the ?? operator it would be much cleaner to pull it out of the calculation expression.

Not coalescing around None-aware

Posted Dec 23, 2022 11:56 UTC (Fri) by rrolls (subscriber, #151126) [Link] (7 responses)

I certainly wouldn't want the operator to exist with the precedence it has in the PEP, but I don't think it's a reason to not have the operator at all - they really just need to fix the precedence.

It's not about putting ?? in absolutely everywhere, either - just making it available for the places where it's useful, and then letting developers choose appropriate places to use it. ?? is no different to walrus, the if-else ternary, lambda functions, generator expressions, or whatever other inline "shorthand" constructions you can think of in that regard. You can easily write ugly code with those if you so choose, just as you can with ??.

For example, a toy "print" function might include "stream.write(msg + end ?? '\n')" - totally readable and the obvious expression to write. Of course, in this case we can just put end='\n' instead of end=None in the function signature, but in more complex real-world cases, where the default might need to be an object or vary depending on circumstances or whatever, that's not always appropriate.

Resolving defaults before doing calculations is something I do all the time in current Python, and it has its downsides - it's extra clutter in the function, and it can be hard to track which variables need to be resolved, which don't, and whether you've missed any, especially if there's a lot of variables involved. Clever type checking code assist helps massively with that, but it's a fairly recent development and it isn't going to work in absolutely all scenarios - for example when extracting data nested deep in the result of a json.load call. Sometimes, it's just cleaner to resolve the defaults inline.

Not coalescing around None-aware

Posted Dec 23, 2022 14:46 UTC (Fri) by shironeko (subscriber, #159952) [Link] (6 responses)

if setting variables to a default value once beforehand is already untrackably messy, how would the programmer have any hope of tracking everywhere the variable is used and "may" be none? the first approach clearly have less or equal things to track than the second approach.

Not coalescing around None-aware

Posted Dec 23, 2022 17:44 UTC (Fri) by rrolls (subscriber, #151126) [Link] (5 responses)

Naturally if you're referring to it more than once you'd resolve the defaults separately beforehand.

There are plenty of examples in the PEP that demonstrate where ?? would be useful far better than I could.

Not coalescing around None-aware

Posted Dec 23, 2022 19:30 UTC (Fri) by shironeko (subscriber, #159952) [Link] (4 responses)

yes I've gone through all the examples in the PEP, pretty much all of them can be solved by not using none and improving the language some other way.

One common example in there is the practice of foo(optional=None) and then assigning a default value to optional right afterwards. clearly this calls for improving the default value syntax not the none operator because it'll still be ugly, just shorter. Maybe the default syntax should accept function call, then we get the added benefit of having the function signature more self documenting than just None and have to figure out what that means.

Not coalescing around None-aware

Posted Dec 24, 2022 6:35 UTC (Sat) by NYKevin (subscriber, #129325) [Link] (3 responses)

> One common example in there is the practice of foo(optional=None) and then assigning a default value to optional right afterwards. clearly this calls for improving the default value syntax not the none operator because it'll still be ugly, just shorter. Maybe the default syntax should accept function call, then we get the added benefit of having the function signature more self documenting than just None and have to figure out what that means.

Improving the default syntax has been discussed endlessly, but it's probably never going to happen, because both of the obvious approaches are non-starters:

1. You can't introduce a new default syntax, because then you would have two default syntaxes, and that has generally been regarded as inferior to the status quo.
2. You can't modify the semantics of the existing syntax, both because it would break backwards compatibility, and also because there is an actual use case for eager evaluation of default values (namely, forcing a closure to eagerly evaluate its closed-over variables) and so you would need to provide an alternative for that. The total amount of ugliness in the language would probably increase.

Not coalescing around None-aware

Posted Dec 24, 2022 6:42 UTC (Sat) by shironeko (subscriber, #159952) [Link] (2 responses)

I'm not quite sure how this could be not backwards compatible because it's allowing something that was not valid python before. I think I'm probably misunderstanding something, can you give an example on how this would cause existing code to break?

Not coalescing around None-aware

Posted Dec 24, 2022 9:12 UTC (Sat) by NYKevin (subscriber, #129325) [Link]

My interpretation of your comment is that you want to allow us to write an arbitrary expression as the default value, and lazily evaluate that expression when the function is called. It is already legal Python syntax to put arbitrary expressions as the default value, so this example will demonstrate the backwards incompatibility of the second half (lazy evaluation) only:

lazy = []
eager = []
for i in range(5):
    lazy.append(lambda: i)
    eager.append(lambda x=i: x)

print(lazy[2]())  # Prints 4
print(eager[2]())  # Prints 2

If you make x=i evaluate lazily, then both versions would print 4. This is backwards incompatible, and it also leaves us with no obvious way to get the 2 behavior instead of the 4 behavior. (Of course, it can be done, but it requires additional boilerplate that nobody should have to write.)

On the other hand, if you are proposing some new syntax that doesn't look like a "regular" Python expression (or somehow "decorates" the default value to indicate that it should be evaluated lazily)... nobody wants to deal with two different default value syntaxes in the same language. That way lies madness.

Not coalescing around None-aware

Posted Dec 24, 2022 9:14 UTC (Sat) by smurf (subscriber, #17840) [Link]

Umm, we're talking about default values to procedure/method arguments here. Of course they're valid Python. They just have semantics that are sub-optimal in THIS case.

Personally I'd just re-purpose the Walrus operator to do lazy evaluation when you (ab)use it in a "def" declaration, though that's probably a non-starter given the past contentious discussion on that topic.

Not coalescing around None-aware

Posted Dec 24, 2022 11:26 UTC (Sat) by k3ninho (subscriber, #50375) [Link] (4 responses)

>I don't buy the arguments that "x ?? y" or "x ??= y" or "x?.y" or "x?[y]" "is unreadable", and I'd make plenty of use of all four of them.

Same, there's stuff I've maintained in js/ts for pulling items out of a nested JSON blob that had to test for each level on the way down, which needed to go through the if parent / if parent.child1 / if parent.child1.child2 stack. This is a pattern that I need in the way I write Python. I'd love this PEP to help me avoid 'index out of range' errors for dictionary errors and attributes.

K3n.

Not coalescing around None-aware

Posted Dec 28, 2022 9:52 UTC (Wed) by kleptog (subscriber, #1183) [Link] (3 responses)

Same here, I'd use them all the time. The current:

a.get('foo', {}).get('bar', {}).get('baz')

gets tedious after a while. And there's no easy equivalent for array indexes so you always have to handle them separately. Something like:

a?['foo']?['bar']?['baz']

is a win in every sense.

Not coalescing around None-aware

Posted Jan 5, 2023 9:43 UTC (Thu) by Karellen (subscriber, #67644) [Link] (2 responses)

Wouldn't it be easier to use an API that takes an XPath-style selector (or similar), where you can ask for a nested element and just get a single result (or None) at the end? e.g:

a.getpath('foo/bar/baz')

Not coalescing around None-aware

Posted Jan 5, 2023 11:10 UTC (Thu) by kleptog (subscriber, #1183) [Link] (1 responses)

I believe any sufficiently advanced Python program eventually evolves a poorly tested, half-baked version of such a getpath() method.

Not coalescing around None-aware

Posted Jan 5, 2023 14:39 UTC (Thu) by smurf (subscriber, #17840) [Link]

Don't forget the dictionary type that affords attribute-style access to its content.

Not coalescing around None-aware

Posted Dec 23, 2022 14:24 UTC (Fri) by geoffhill (subscriber, #92577) [Link] (2 responses)

Stop adding syntax to Python!!!

This isn’t just about all the syntax-aware programs, libraries and models that will need updating.

Every language addition, however minor, has the potential to change the idiomatic style and practices of the language.

When that happens, it creates a huge amount of tech debt to refactor all non-idiomatic code in existence, and it reduces the average existing Python programmer’s language familiarity.

Syntax changes risks changing the character of the language that made it so popular in the first place.

Just stop!!!

Not coalescing around None-aware

Posted Dec 23, 2022 17:17 UTC (Fri) by pwfxq (subscriber, #84695) [Link]

+1

> ...noting that multiple languages (JavaScript, Flutter, Kotlin, and C#) already have it

Just because other languages have a feature doesn't mean the Python language should adopt it.

Personally I'm not in favour of adding this ever so slightly cryptic syntax to Python.

Not coalescing around None-aware

Posted Dec 25, 2022 16:36 UTC (Sun) by caliloo (subscriber, #50055) [Link]

+1

one of the main feature of python imho is ease of learning. Adding more operators for those who have 5 -10 years experience in it and just want to code faster those places where checking for none is justified does not seem to me like the spirit of python.

Not coalescing around None-aware

Posted Dec 23, 2022 22:39 UTC (Fri) by ballombe (subscriber, #9523) [Link]

It happens that I maintain a language where None is handled entirely inside the runtime and is not visible in the language.
You can do
fun(a,b=foo(a)) = { ... }
and foo(a) is only evaluated if b is not given,
that is, fun(A) will lead to foo(A) being evaluated but not fun(A,B).

This seems nice, but there is a defect: suppose you now have a function fun2 calling fun:
fun2(c,a,b) = { ... fun(a,b) ... }
then b become mandatory in fun2. The way to have b optional is to write
fun2(c,a,b=foo(a)) = { ...; fun(a,b); ... }
repeating the code to compute the default value.

If None was allowed, then the function could be written as
fun2(c,a,b=None) = { ...; fun(a,b); ... }

Not coalescing around None-aware

Posted Dec 25, 2022 17:50 UTC (Sun) by caliloo (subscriber, #50055) [Link] (14 responses)

One funny thing I note is that
If x is none:
x=42

Is actually less characters than
x = 42 if x is none else x

x=?? 42
Is of course shorter, but readability will depend on your proficiency in python operators, which implies a greater prerequisite on your knowledge of python.

Besides, having condition and assignment on 2 different lines fits more with the rhythm of python overall, I think.(I know, list comprehensions, lambdas…)

I often find that full time somewhat experienced programmers enter a race in the least number of lines/chars at the expense of everything else (functional form in Java for example, or Perl, or user defined ops in cpp) When you start wielding this hammer you tend to find nails naturally, because you re at a level of knowledge where typing less advantages you. But this vantage point from which the balance advantages/inconvenients is measured is not the only one. One of the strength of python is that people can be onboarded easily, or not make programming their full time job. From these other pov I’d say that the most advantageous form if the first one.

I wonder if there wouldn’t also be an advantage to explicitly make a subset of python “advanced features” enableable with a flag or some such thing. But I don’t have any personal experience in such way of doing things personally.

I’d be curious though to see if the balance of users keeps shifting towards full time programmers as it has for the past decade or more. This would reshuffle the cards on how to make that choice in my opinion.

Not coalescing around None-aware

Posted Dec 25, 2022 22:33 UTC (Sun) by Wol (subscriber, #4433) [Link] (12 responses)

> I’d be curious though to see if the balance of users keeps shifting towards full time programmers as it has for the past decade or more. This would reshuffle the cards on how to make that choice in my opinion.

The problem with that, is that it makes programmers an elite. Which actually leads to bad systems! We have programmers who don't know what the program is for, we have users who can't program, and we have business analysts - sorry chinese whisperers - who are trying to square the circle.

Cue a big disastrous mess ...

Cheers,
Wol

Not coalescing around None-aware

Posted Dec 26, 2022 2:04 UTC (Mon) by NYKevin (subscriber, #129325) [Link] (11 responses)

We've been trying to build real* programming languages for non-programmers since the days of COBOL. Every single one of those languages, without exception, has eventually evolved in one of two directions:

1. Programmers use it, business analysts don't, it starts being treated like a "real" programming language, and eventually everyone forgets that it was a "for non-programmers" language in the first place. At most, it will retain some funny-looking syntax or quirks of semantics. E.g. PHP, SQL, COBOL, BASIC.
2. Programmers use it, business analysts don't, but everyone pretends otherwise and insists on keeping it "friendly" to non-programmers, to the detriment of the system's usability. At best it becomes a niche system used by one or two very large organizations for some highly specialized purpose. Regardless, nobody else will touch it with a ten foot pole. I don't have examples, because these things are usually proprietary and nearly always NDA'd out the wazoo. GUI interfaces are common. Branching may be represented using flow charts. You may have to construct individual lines of code by picking instructions and operands out of drop-down boxes. Etc.

Learning to code is challenging for many people. But it is not "the hard part" of programming. The hard part is learning to reason about the logical implications of code. Learning to boil down a user story (or whatever they're calling them these days) into a logically rigorous set of functional and non-functional requirements, and ensuring that each module of the larger whole upholds its end of the bargain. No amount of hand waving will convince the computer that it should "just do what I want." Even with AI, there will always be a conceptual gap between what you want, and what you ask for. AI is not magic. It cannot read your mind. And neither can "friendly" user interfaces.

* "Real" = "not just an educational toy like Scratch, but a proper language you might try to use for serious purposes."

Not coalescing around None-aware

Posted Dec 26, 2022 9:26 UTC (Mon) by Wol (subscriber, #4433) [Link]

> * "Real" = "not just an educational toy like Scratch, but a proper language you might try to use for serious purposes."

I can name one (of course). DataBASIC. There are plenty of systems that were written in that. Pretty much the entire travel industry. HOLMES. A bit of digging could find plenty more. And there are plenty of horror stories about the disasters as people tried to migrate away from this "niche" system that was embedded everywhere that nobody knew about ...

But the problem was Dick Pick spent his money on lawyers, not marketeers, and SQL took over :-(

Cheers,
Wol

Not coalescing around None-aware

Posted Dec 26, 2022 10:19 UTC (Mon) by caliloo (subscriber, #50055) [Link] (1 responses)

Lol the description you make in point 2 sounds too much like magic the ide/programming env for comfort

Not coalescing around None-aware

Posted Dec 26, 2022 17:38 UTC (Mon) by NYKevin (subscriber, #129325) [Link]

I was primarily thinking of [1], but having briefly worked a consulting gig, I can assure you that systems like that one are actually deployed in the wild (but I can't give any details, for obvious reasons). Alex didn't just make it up from whole cloth or something (a frequent accusation people level against that site).

[1]: https://thedailywtf.com/articles/The_Customer-Friendly_Sy...

Not coalescing around None-aware

Posted Dec 28, 2022 1:16 UTC (Wed) by MrWim (subscriber, #47432) [Link] (7 responses)

Spreadsheets are a counterexample. People who wouldn’t consider themselves programmers program with them every day - and don’t think of themselves as programming while they do it.

Not coalescing around None-aware

Posted Dec 28, 2022 10:07 UTC (Wed) by Wol (subscriber, #4433) [Link] (6 responses)

As an experienced database guy now responsible for Excel as our departmental database , I would beg to differ ...

I'm a novice at VBA and the number of landmines is atrocious. Excel is not a database.

Our whole system is a mess, and I doubt it's any worse than any other big corp out there ...

A lot of my work is finding and fixing design and data errors ...

Cheers,
Wol

Not coalescing around None-aware

Posted Dec 28, 2022 14:44 UTC (Wed) by MrWim (subscriber, #47432) [Link] (5 responses)

I wasn’t really thinking about VBA - I was referring to the spreadsheet itself as a functional programming environment.

Not coalescing around None-aware

Posted Dec 28, 2022 16:33 UTC (Wed) by Wol (subscriber, #4433) [Link] (4 responses)

Functional? Just barely!!!

The problem basically is that any use of a spreadsheet beyond the elementary is probably using it as a database - a role for which it is particularly badly suited. (You know my views on relational :-) also equally badly suited for database TECHNOLOGY :-)

Throw into the mix people who don't know how to program, and the result is a complete mess. Even if they do know how to program, you know the saying ... "if all you have is a hammer, every problem looks like a nail ..."

Cheers,
Wol

Not coalescing around None-aware

Posted Feb 25, 2023 0:17 UTC (Sat) by nix (subscriber, #2304) [Link] (3 responses)

I am reliably informed that for a number of years in the 1990s the system that decided how to route high-voltage power across the UK was... an Excel spreadsheet (translated from creaky old Fortran by a friend of mine).

The lack of major fires, explosions, and large-scale power cuts in the 1990s suggests that this crazy lash-up did in fact work.

Not coalescing around None-aware

Posted Feb 25, 2023 7:42 UTC (Sat) by donald.buczek (subscriber, #112892) [Link]

> The lack of major fires, explosions, and large-scale power cuts in the 1990s suggests that this crazy lash-up did in fact work.

This is a single example and it is diffucult to research how many (if any) problems were caused by this choice.

See https://thenextweb.com/news/excel-autocorrect-errors-plag... down to "Spreadsheet catastrophes" for some counter-examples.

Not coalescing around None-aware

Posted Feb 25, 2023 11:18 UTC (Sat) by Wol (subscriber, #4433) [Link] (1 responses)

Was the guy who ported it a Fortran programmer?

Written by a guy who understood programming, that sheet was probably a well designed database with a programming language. Everything needed to do a good job.

There are far better tools out there, but a decent tool in the hands of competent tool can get you far ...

The right tool in the hands of an expert, well that's another kettle of fish!

Cheers,
Wol

Not coalescing around None-aware

Posted Feb 25, 2023 12:14 UTC (Sat) by Wol (subscriber, #4433) [Link]

> decent tool in the hands of competent tool

Whoops ...

decent tool in the hands of a competent expert

Cheers,
Wol

Not coalescing around None-aware

Posted Dec 26, 2022 23:56 UTC (Mon) by pm215 (subscriber, #98099) [Link]

I think one key set of users for whom "not too much clever shorthand syntax" is useful is the programmers who have to dabble in python as a secondary language that *isn't* the one they program in most of the time. Small scripts, interpreters embedded into other programs, that sort of thing -- at the moment Python is pretty good for this because (among other things) if you know programming-in-general then what a lump of Python does is mostly fairly self-explanatory.

Not coalescing around None-aware

Posted Dec 28, 2022 9:22 UTC (Wed) by tialaramex (subscriber, #21167) [Link] (6 responses)

I have been convinced for some time that languages without Sum types end up with these workarounds and the price of one such workaround is attractive, but there are a lot of useful Sum types, and it becomes unwieldy to implement a workaround for each.

"None-aware operators" are a workaround for lacking Option / Maybe / the "... | None" ad hoc type.

Exceptions are a workaround for lacking Result / Expect

Languages should bite the bullet and provide Sum types even though that's a lot of work.

Not coalescing around None-aware

Posted Dec 28, 2022 21:55 UTC (Wed) by NYKevin (subscriber, #129325) [Link] (5 responses)

Python does support Sum types. In fact, the only (static) type in the language is PyObject*, which is just a Sum over all possible types.

The real problem is that Python is dynamic, and "supporting Sum types" doesn't mean anything in the context of dynamic languages. Well, not unless you want to build some kind of wrapper object that really exists at runtime and can't be monomorphized away. But you don't need language-level support for that, you can Just Do It.

Not coalescing around None-aware

Posted Dec 29, 2022 2:21 UTC (Thu) by tialaramex (subscriber, #21167) [Link] (4 responses)

I guess that yeah, maybe the problem is the dynamism. If I have a Dog type then I can intentionally narrow from Dog | None to just Dog and then write code which knows it's a Dog, not a None. Python doesn't want that, it reminds me of the .NET CLR. Modern CLR languages tend to have explicit nullability, so we can say this is a Dog, and really mean that - it isn't a null Dog, it's definitely a Dog. But the CLR itself doesn't admit this idea, and so all .NET programs must defend against APIs receiving a null even where they explicitly said it wasn't welcome. Your function which takes an integer definitely doesn't get floating point parameters, but your function which takes a (non-null) Dog, can still get fed a null Dog by an older or malevolent program.

Not coalescing around None-aware

Posted Dec 29, 2022 8:20 UTC (Thu) by smurf (subscriber, #17840) [Link] (3 responses)

Python explicitly supports duck-typing. If your non-Dog-derived object barks like a dog, then "dog.bark()" works even if it's a lyrebird. The song-and-dance you need to go through in C++ or Java to achieve that kind of flexibility (among many other common patterns that tend to take one line in Python, a new class in C++, and two source files in Java) is exactly why I'm using Python.

There are ways to declare interfaces for that kind of code; however, if you want to find typing problems statically instead of crashing on them, Python wants you to use a separate checker (like mypy).

Not coalescing around None-aware

Posted Dec 29, 2022 13:12 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

I feel like this greatly depends on the kind of software you're writing. I tend to write "libraries" where reliability is higher on the list than applications which can be more of "we're all good fellas around here *nudge* *wink*" with respect to what you can be given as an argument. Given the kinds of craziness Python ducks can contain, I find it much easier to have that "I only accept types which explicitly claim to support interface X" hurdle. Of course, some languages make it a PITA (C++ and Java require inheritance, but Rust and Haskell can get these tacked on later with `impl Trait`-like blocks), but not every feature comes with every creature either.

Not coalescing around None-aware

Posted Dec 29, 2022 20:42 UTC (Thu) by tialaramex (subscriber, #21167) [Link] (1 responses)

Duck typing is perhaps an appropriate convenience for Python, a language for non-programmers, but what happens is we're polluting a namespace. Having a bark() method does *not* mean you bark "like a dog" but once this unstated assumption takes hold everybody is stuck with it.

This pollution has become pretty bad in C++ where on top of about 100 reserved words like "for" and "reinterpret_cast" and "co_await" there are a vast number of in practice unavailable identifier names which, if you make the mistake of using them, implicitly mark the affected type as having specific properties associated with that word e.g. cbegin() means you're able to provide a constant iterator, size() means you're some container with things inside it. Even though C++ doesn't "Have" duck typing in this respect in practice that's what it does.

Better, I am confident, to be able to state explicitly what you mean, if this Lyre Bird can in fact smurf::animal-noises::Dog::bark that's fine, but it shouldn't be confused with my tialaramex::army::DrillSergeant::bark which is provided neither by Lyre Birds nor Dogs. We need to be clear what is meant.

core::cmp::Ordering and core::sync::atomic::Ordering are both really, really important, but in their own context. Just because my sort method needs an Ordering and your spinlock code has an Ordering doesn't mean they're concerned with the same thing. If the two are in adjacent code, that code needs to spell out what's going on. In unrelated code, the expectation can be stated just once and then context is clear afterwards.

Not coalescing around None-aware

Posted Dec 29, 2022 21:56 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

> Even though C++ doesn't "Have" duck typing in this respect in practice that's what it does.

The mechanism of templating in C++ basically feels like it (since it feels a lot like "structured preprocessor" more than "provides interface"). Concepts should help, but standard library usage remains to be seen.

Not coalescing around None-aware

Posted Dec 29, 2022 16:01 UTC (Thu) by NRArnot (subscriber, #3033) [Link]

In almost all contexts you can do
  x = x or default
the exception being where x may have a falsy value which is not None and which you do not want to replace.

In all contexts you can do
  ( default if x is None else x)

I for one don't find the case for a slew of new operators overwhelming. I'm not sure they enhance code readability, and the above are not particularly verbose.


Copyright © 2022, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds