-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
PEP 824: Coalescing operators #4799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
nschneid
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a few typos
|
@gvanrossum And please can you confirm sponsorship of this as well as #4798? |
Yes of course. |
gvanrossum
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I love that these get a serious treatment and I hope we can get the PEP to make it into 3.15. Again I have some editorial suggestions (some of which are generic and could apply to 823 as well) and some grammar nits and typos.
| This PEP proposes adding two new operators. | ||
|
|
||
| * The "``None`` coalescing" operator ``??`` | ||
| * The "Coalescing assignment" operator ``??=`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we twist our mind so the operator names are more similar? I'd like both to be known as None-coalescing or both as coalescing. (And honestly I don't know what "coalescing" means, really, except for this precise case.)
In JavaScript it appear they are called the nullish coalescing operator (??) and the nullish coalescing assignment operator (??=). (Null-ish because they treat undefined and null the same way. But no other falsy values.)
For C# I see: The ?? and ??= operators are the C# null-coalescing operators.
|
|
||
| The coalescing operators are **opt-in**. Existing programs will | ||
| continue to run as is. So far code which used either ``??`` or ``??=`` | ||
| raised a ``SyntaxError``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just state that ? is not allowed by the current Python grammar? (Also for 823 -- there's an annoying amount of duplication between the two PEPs that makes me think that maybe they ought to be coalesced again. ;-)
Which makes me think that maybe we should look if there are 3rd party macro systems for Python that do use ? ?
| Security Implications | ||
| ===================== | ||
|
|
||
| There are no new security implications from this proposal. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except for applications reserving ? or ?? for themselves perhaps?
peps/pep-0824.rst
Outdated
| In a practical sense it might be helpful to think of the "``None`` | ||
| coalescing" operator ``??`` as a special case for the conditional ``or`` | ||
| operator, with the caveat that ``??`` checks for ``is not None`` instead | ||
| of truthiness. As such it makes sense to include ``??`` when teaching | ||
| about the other conditional operators ``and`` and ``or``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed! It's super simple to explain. (Except that the shortcut behavior of or and the idioms around it are arguably a somewhat advanced topic.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these advanced usage distinctions are important to cover in the documentation. Choosing between or and ?? is inherently context-dependent, and clear guidance on when None is appropriate — versus when a neutral default leads to a cleaner API — would be valuable.
Documenting this distinction helps ensure ?? is most useful without than encouraging broader reliance on None. This was a key concern raised during discussion of pep 505, so addressing it directly would strengthen the proposal.
For example:
While
Noneis a convenient way to signal absence, it is not always the best default When a type has a natural identity or neutral value that already represents an "empty" state, introducingNonecan add unnecessary branching and complexity.
In such cases, using that neutral value and relying on truthiness withoroften leads to simpler, more idiomatic code:def show_pet_name(name: str = ""): print("Pet name:", name or random_name())Here, the empty string is a reasonable default because it clearly represents "no name provided."
In contrast, sometimes every value of a type — including its neutral value — is semantically meaningful. In those cases,
Noneserves as an explicit sentinel representing absence. This is where the None-coalescing operators are more appropriate:def set_room_temperature(temperature: int | None = None): print("Setting thermostat to", temperature ?? calculate_regional_default())In this example, 0 could be a valid temperature setting, so using
orwould be incorrect;??preserves the distinction between an explicit value and no value at all.
| The "coalescing assignment" ``??=`` operator can be best thought of as | ||
| a conditional assignment operator. As it is closely related to ``??`` | ||
| explaining these together would make sense. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say x ??= y is to x ?? y as x += y is to x + y. IOW, x ??= y means x = x ?? y. No more needs to be said.
| https://github.com/cdce8p/cpython/tree/pep-XXX. A online demo can be | ||
| tested at https://pepXXX-demo.pages.dev/. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, these 404 for me.
Hnasar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for writing this up in such a clear way. Exciting to see this move forward!
peps/pep-0824.rst
Outdated
| One of the reasons why :pep:`505` stalled was that some expressed their | ||
| concern how coalescing and ``None``-aware operators will affect the code | ||
| written by developers. If it is easier to work with ``None`` values, | ||
| this will encourage developers to use them more. They believe that | ||
| e.g. returning an optional ``None`` value from a function is usually an | ||
| anti-pattern. In an ideal world the use of ``None`` would be limited as | ||
| much as possible, for example with early data validation. | ||
|
|
||
| It is certainly true that new language features affect how the language | ||
| as a whole develops. Therefore any changes should be considered carefully. | ||
| However, just because ``None`` represents an anti-pattern for some, has | ||
| not prevented the community as a whole from using it extensively. Rather | ||
| the lack of coalescing operators has stopped developers from writing | ||
| concise expressions and instead often leads to more complex code or such | ||
| which can contain subtle errors, see the `Motivation`_ section for more | ||
| details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Some of this concern has also been raised by the original author of PEP 505 e.g. in 2021 and again in 2025)
suggestion: Expanding the discussion of this viewpoint would strengthen the proposal. A more thorough treatment of the risks and trade-offs around encouraging None-centric APIs would make the case more balanced and persuasive.
(For context on my own bias: I’ve grown to appreciate None-free API design over time, though I do think ?? can be valuable in the right situations. My hope is that this PEP clearly steers usage toward those situations and away from patterns that could lead to subtle misuse.)
| One of the reasons why :pep:`505` stalled was that some expressed their | |
| concern how coalescing and ``None``-aware operators will affect the code | |
| written by developers. If it is easier to work with ``None`` values, | |
| this will encourage developers to use them more. They believe that | |
| e.g. returning an optional ``None`` value from a function is usually an | |
| anti-pattern. In an ideal world the use of ``None`` would be limited as | |
| much as possible, for example with early data validation. | |
| It is certainly true that new language features affect how the language | |
| as a whole develops. Therefore any changes should be considered carefully. | |
| However, just because ``None`` represents an anti-pattern for some, has | |
| not prevented the community as a whole from using it extensively. Rather | |
| the lack of coalescing operators has stopped developers from writing | |
| concise expressions and instead often leads to more complex code or such | |
| which can contain subtle errors, see the `Motivation`_ section for more | |
| details. | |
| One reason :pep:`505` ultimately stalled was concern that introducing | |
| ``None``-coalescing operators would normalize and thereby encourage | |
| ``None``-centric APIs, rather than promoting ``None``-free interface | |
| designs. Such designs favor well-defined identity or neutral objects | |
| (e.g. ``0`` and ``""``) or, alternatively, surface failure through exceptions. | |
| It is certainly true that new language features affect how the language | |
| and its idioms evolve, and this concern deserves careful consideration. | |
| While ``None`` can be the most appropriate representation of absence in | |
| some cases, it is also widely used today in situations where a neutral | |
| value or a different design might lead to clearer APIs. The lack of | |
| coalescing operators can make such code more verbose, but adding them | |
| also risks making ``None`` the path of least resistance. | |
| To address this, as noted in the “How to Teach This” section, the | |
| documentation should explicitly discuss when ``None`` and coalescing | |
| operators are appropriate and when a neutral default or alternative | |
| design is preferable. |
On the the 'subtle errors' point: sometimes None can prevent bugs, but other times, introduce them by allowing neutral values which should be invalid. For example, I've seen a real-world outage caused by this type of logic bug, which is more likely with None-coalescing operators (and would be avoided with or):
def remove_cache(path: str | None):
- path or expensive_function_to_find_cache()
+ path ??= expensive_function_to_find_cache()
shutil.rmtree(Path(path))With such a change, if this function is called as remove_cache(""), the empty string is not None, so the fallback is skipped and the current working directory may be removed (I have unfortunately seen this exact bug). Code written with or would behave differently here, which illustrates why guidance on choosing between falsey defaults and None is important.
peps/pep-0824.rst
Outdated
| In a practical sense it might be helpful to think of the "``None`` | ||
| coalescing" operator ``??`` as a special case for the conditional ``or`` | ||
| operator, with the caveat that ``??`` checks for ``is not None`` instead | ||
| of truthiness. As such it makes sense to include ``??`` when teaching | ||
| about the other conditional operators ``and`` and ``or``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these advanced usage distinctions are important to cover in the documentation. Choosing between or and ?? is inherently context-dependent, and clear guidance on when None is appropriate — versus when a neutral default leads to a cleaner API — would be valuable.
Documenting this distinction helps ensure ?? is most useful without than encouraging broader reliance on None. This was a key concern raised during discussion of pep 505, so addressing it directly would strengthen the proposal.
For example:
While
Noneis a convenient way to signal absence, it is not always the best default When a type has a natural identity or neutral value that already represents an "empty" state, introducingNonecan add unnecessary branching and complexity.
In such cases, using that neutral value and relying on truthiness withoroften leads to simpler, more idiomatic code:def show_pet_name(name: str = ""): print("Pet name:", name or random_name())Here, the empty string is a reasonable default because it clearly represents "no name provided."
In contrast, sometimes every value of a type — including its neutral value — is semantically meaningful. In those cases,
Noneserves as an explicit sentinel representing absence. This is where the None-coalescing operators are more appropriate:def set_room_temperature(temperature: int | None = None): print("Setting thermostat to", temperature ?? calculate_regional_default())In this example, 0 could be a valid temperature setting, so using
orwould be incorrect;??preserves the distinction between an explicit value and no value at all.
Basic requirements (all PEP Types)
pep-NNNN.rst), PR title (PEP 123: <Title of PEP>) andPEPheaderAuthororSponsor, and formally confirmed their approvalAuthor,Status(Draft),TypeandCreatedheaders filled out correctlyPEP-Delegate,Topic,RequiresandReplacesheaders completed if appropriate.github/CODEOWNERSfor the PEPStandards Track requirements
Python-Versionset to valid (pre-beta) future Python version, if relevantDiscussions-ToandPost-History📚 Documentation preview 📚: https://pep-previews--4799.org.readthedocs.build/