I’m new here, but I did a search and wasn’t able to find anything in this forum on PEP 505 (https://www.python.org/dev/peps/pep-0505/). Is this PEP dead? or just unloved? The page says “deferred” but it doesn’t explain why.
PEP 505 is controversial as it’s using ?
(the question mark), one of the last few printable non-alphanumeric characters from the 7-bit ASCII subset. The other example being $
(the dollar sign).
You can search archives of the python-ideas and python-dev mailing lists for previous discussion on this PEP.
It was mostly controversial because nobody agreed on whether “None” was special or not.
The conversation didn’t make it to python-dev, but searching python-ideas for “PEP 505” should find the last round of discussion.
Thanks all. I’ll take a look there.
I think most deferred PEPs have a small writeup in a section titled “PEP defferal” or something similar right at the top. Would it be possible to add something similar to this PEP?
That seems absurd to me. I was just looking for discussion about it to suggest adding a typing
addition for Optional
where you could have a type annotation using the None
-aware syntax (e.g., def test(a: int?):
).
Was there a feeling of consensus from other core devs? Were there more people in favor than not?
I am not a core dev, but I feel the community consensus is that None
is not “special enough” to warrant a new syntax, but def test(a: int | None)
is good enough (which is going to happen in 3.10).
Being one of four singletons builtin, it seems pretty special. That’s good to know about the new syntax, though. I like that. Null operators would still help ergonomics a lot especially as I swap between C#/Rust and Python at work these days quite a bit.
I hope this PEP is revived. I think the ergonomic and type-safety value of safe ? references justify making None
special even if it isn’t currently considered to be so.
As others noted, the main semantic sticking point was that the specific is None
check was seen as too limiting, but the proposals to offer a more flexible underlying protocol based approach (e.g. https://www.python.org/dev/peps/pep-0532 ) were seen as too complicated. (There was also a syntactic sticking point, which is that ??
, ?.
, and ?[]
don’t really meet anyone’s definition of “executable pseudocode”, which is a standard we aspire to for new Python syntax)
Something we didn’t seriously consider at the time, but may want to think about now is whether making the short circuiting check be for x == None
rather than x is None
might offer enough runtime flexibility to get past the "None
is special, but it isn’t that special" objection.
While most of the arguments for withdrawing PEP 531 (https://www.python.org/dev/peps/pep-0531/#pep-withdrawal) would also applying to defining PEP 505 that way (since x == None
would effectively become the “existence checking protocol” that PEP 531 suggested), it might be more palatable when it’s just adapting an existing protocol to a new purpose, rather than defining a completely new one.
Hello all!
I was wondering - what was the justification behind Python core developers rejecting maybe
builtin in PEP 505? At first glance, it meets the pro tanto criterion of “executable pseudocode” for syntax additions to Python, makes an obnoxious idiom much more readable, and can trace its homage to a well-known feature in Haskell:
data = [] if data is None else data
files = [] if files is None else files
headers = {} if headers is None else headers
to
data = maybe data else []
files = maybe files else []
headers = maybe headers else {}
That’s a question for the PEP authors, as they are the ones who have rejected a “maybe” builtin.
But some thoughts come to mind.
First, we need to distinguish between a maybe
builtin type and a “maybe” builtin operator.
You seem to be asking about a maybe operator:
data = maybe data else []
This is a binary operator (it takes two arguments, data
and []
) but it is written using two keywords, one prefix maybe data
and one infix data else []
. That seems extravagently verbose, possibly even wasteful.
Python code often reads like executable pseudocode, but not like natural language. Using two keywords for a binary operator is something I would expect from a language like Hypertalk, where we might write things like:
add 1 to x
put 2*x into y
Also, as a native English speaker, the else
part doesn’t feel right to me. maybe data or []
reads better, but of course that leads to precedence issues with the binary or
operator.
Most other languages with a null-coalescing operator seem to be converging on using question marks. It seems wasteful to use two key words to accomplish what a single infix symbol can do:
data ?? []
maybe data else []
And how would you chain these expressions?
data ?? info ?? []
maybe data else maybe info else []
maybe maybe data else info else []
And what about the maybe dot operator?
a?.b(c)
Coming back to the PEP, I’m not one of the authors but my reading of that section is that pymaybe
has a function maybe()
that returns either a Something
instance or a Nothing
instance. The PEP suggests that instead of using a function and two types, they could use a single builtin maybe
type to work the same way.
The PEP already gives the disadvantages of this:
I expect that getting this sort of proxying right is much harder than giving the interpreter a binary infix operator ??
and supporting chaining.
The Haskell docs for maybe
might as well be written in Martian. But if I am interpreting them correctly, it seems that maybe
is used for falsey/truthy checks, with the added twist that you can define any values you like as falsey. Using the word maybe
may mislead people into thinking we have Haskell’s maybe
functor when we don’t.
Perhaps maybe
could go to much shallower lengths than Haskell-esque pymaybe
? Consider something like this:
def maybe(nullable, *args):
"""A 'readable pseudo-code' implementation of null-coalescing operator (??)."""
for j in (i for i in [nullable, *args] if i is not None):
return j
Now we’re comparing:
data = data if data is not None else info if info is not None else []
files = [] if files is None else files
headers = {} if headers is None else headers
to
data = maybe(data, info, [])
files = maybe(files, [])
headers = maybe(headers, {})