python-peps/pep-0531/index.html

757 lines
65 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 531 Existence checking operators | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0531/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 531 Existence checking operators | peps.python.org'>
<meta property="og:description" content="Inspired by PEP 505 and the related discussions, this PEP proposes the addition of two new control flow operators to Python:">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0531/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Inspired by PEP 505 and the related discussions, this PEP proposes the addition of two new control flow operators to Python:">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 531</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 531 Existence checking operators</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Alyssa Coghlan &lt;ncoghlan&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Removed from consideration by sponsor or authors">Withdrawn</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">25-Oct-2016</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.7</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">28-Oct-2016</dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#pep-withdrawal">PEP Withdrawal</a></li>
<li><a class="reference internal" href="#relationship-with-other-peps">Relationship with other PEPs</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#existence-checking-expressions">Existence checking expressions</a></li>
<li><a class="reference internal" href="#existence-checking-assignment">Existence checking assignment</a></li>
<li><a class="reference internal" href="#existence-checking-protocol">Existence checking protocol</a></li>
<li><a class="reference internal" href="#proposed-symbolic-notation">Proposed symbolic notation</a></li>
<li><a class="reference internal" href="#proposed-keywords">Proposed keywords</a></li>
</ul>
</li>
<li><a class="reference internal" href="#risks-and-concerns">Risks and concerns</a><ul>
<li><a class="reference internal" href="#readability">Readability</a></li>
<li><a class="reference internal" href="#magic-syntax">Magic syntax</a></li>
<li><a class="reference internal" href="#conceptual-complexity">Conceptual complexity</a></li>
</ul>
</li>
<li><a class="reference internal" href="#design-discussion">Design Discussion</a><ul>
<li><a class="reference internal" href="#subtleties-in-chaining-existence-checking-expressions">Subtleties in chaining existence checking expressions</a></li>
<li><a class="reference internal" href="#ambiguous-interaction-with-conditional-expressions">Ambiguous interaction with conditional expressions</a></li>
<li><a class="reference internal" href="#existence-checking-in-other-truth-checking-contexts">Existence checking in other truth-checking contexts</a></li>
<li><a class="reference internal" href="#defining-expected-invariant-relations-between-bool-and-exists">Defining expected invariant relations between <code class="docutils literal notranslate"><span class="pre">__bool__</span></code> and <code class="docutils literal notranslate"><span class="pre">__exists__</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#limitations">Limitations</a><ul>
<li><a class="reference internal" href="#arbitrary-sentinel-objects">Arbitrary sentinel objects</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>Inspired by <a class="pep reference internal" href="../pep-0505/" title="PEP 505 None-aware operators">PEP 505</a> and the related discussions, this PEP proposes the addition
of two new control flow operators to Python:</p>
<ul class="simple">
<li>Existence-checking precondition (“exists-then”): <code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">?then</span> <span class="pre">expr2</span></code></li>
<li>Existence-checking fallback (“exists-else”): <code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">?else</span> <span class="pre">expr2</span></code></li>
</ul>
<p>as well as the following abbreviations for common existence checking
expressions and statements:</p>
<ul class="simple">
<li>Existence-checking attribute access:
<code class="docutils literal notranslate"><span class="pre">obj?.attr</span></code> (for <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">?then</span> <span class="pre">obj.attr</span></code>)</li>
<li>Existence-checking subscripting:
<code class="docutils literal notranslate"><span class="pre">obj?[expr]</span></code> (for <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">?then</span> <span class="pre">obj[expr]</span></code>)</li>
<li>Existence-checking assignment:
<code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">?=</span> <span class="pre">expr</span></code> (for <code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">value</span> <span class="pre">?else</span> <span class="pre">expr</span></code>)</li>
</ul>
<p>The common <code class="docutils literal notranslate"><span class="pre">?</span></code> symbol in these new operator definitions indicates that they
use a new “existence checking” protocol rather than the established
truth-checking protocol used by if statements, while loops, comprehensions,
generator expressions, conditional expressions, logical conjunction, and
logical disjunction.</p>
<p>This new protocol would be made available as <code class="docutils literal notranslate"><span class="pre">operator.exists</span></code>, with the
following characteristics:</p>
<ul class="simple">
<li>types can define a new <code class="docutils literal notranslate"><span class="pre">__exists__</span></code> magic method (Python) or
<code class="docutils literal notranslate"><span class="pre">tp_exists</span></code> slot (C) to override the default behaviour. This optional
method has the same signature and possible return values as <code class="docutils literal notranslate"><span class="pre">__bool__</span></code>.</li>
<li><code class="docutils literal notranslate"><span class="pre">operator.exists(None)</span></code> returns <code class="docutils literal notranslate"><span class="pre">False</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">operator.exists(NotImplemented)</span></code> returns <code class="docutils literal notranslate"><span class="pre">False</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">operator.exists(Ellipsis)</span></code> returns <code class="docutils literal notranslate"><span class="pre">False</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">float</span></code>, <code class="docutils literal notranslate"><span class="pre">complex</span></code> and <code class="docutils literal notranslate"><span class="pre">decimal.Decimal</span></code> will override the existence
check such that <code class="docutils literal notranslate"><span class="pre">NaN</span></code> values return <code class="docutils literal notranslate"><span class="pre">False</span></code> and other values (including
zero values) return <code class="docutils literal notranslate"><span class="pre">True</span></code></li>
<li>for any other type, <code class="docutils literal notranslate"><span class="pre">operator.exists(obj)</span></code> returns True by default. Most
importantly, values that evaluate to False in a truth checking context
(zeroes, empty containers) will still evaluate to True in an existence
checking context</li>
</ul>
</section>
<section id="pep-withdrawal">
<h2><a class="toc-backref" href="#pep-withdrawal" role="doc-backlink">PEP Withdrawal</a></h2>
<p>When posting this PEP for discussion on python-ideas <a class="footnote-reference brackets" href="#id10" id="id1">[4]</a>, I asked reviewers to
consider 3 high level design questions before moving on to considering the
specifics of this particular syntactic proposal:</p>
<p>1. Do we collectively agree that “existence checking” is a useful
general concept that exists in software development and is distinct
from the concept of “truth checking”?
2. Do we collectively agree that the Python ecosystem would benefit
from an existence checking protocol that permits generalisation of
algorithms (especially short circuiting ones) across different “data
missing” indicators, including those defined in the language
definition, the standard library, and custom user code?
3. Do we collectively agree that it would be easier to use such a
protocol effectively if existence-checking equivalents to the
truth-checking “and” and “or” control flow operators were available?</p>
<p>While the answers to the first question were generally positive, it quickly
became clear that the answer to the second question is “No”.</p>
<p>Steven DAprano articulated the counter-argument well in <a class="footnote-reference brackets" href="#id11" id="id2">[5]</a>, but the general
idea is that when checking for “missing data” sentinels, were almost always
looking for a <em>specific</em> sentinel value, rather than <em>any</em> sentinel value.</p>
<p><code class="docutils literal notranslate"><span class="pre">NotImplemented</span></code> exists, for example, due to <code class="docutils literal notranslate"><span class="pre">None</span></code> being a potentially
legitimate result from overloaded arithmetic operators and exception
handling imposing too much runtime overhead to be useful for operand coercion.</p>
<p>Similarly, <code class="docutils literal notranslate"><span class="pre">Ellipsis</span></code> exists for multi-dimensional slicing support due to
<code class="docutils literal notranslate"><span class="pre">None</span></code> already have another meaning in a slicing context (indicating the use
of the default start or stop indices, or the default step size).</p>
<p>In mathematics, the value of <code class="docutils literal notranslate"><span class="pre">NaN</span></code> is that <em>programmatically</em> it behaves
like a normal value of its type (e.g. exposing all the usual attributes and
methods), while arithmetically it behaves according to the mathematical rules
for handling <code class="docutils literal notranslate"><span class="pre">NaN</span></code> values.</p>
<p>With that core design concept invalidated, the proposal as a whole doesnt
make sense, and it is accordingly withdrawn.</p>
<p>However, the discussion of the proposal did prompt consideration of a potential
protocol based approach to make the existing <code class="docutils literal notranslate"><span class="pre">and</span></code>, <code class="docutils literal notranslate"><span class="pre">or</span></code> and <code class="docutils literal notranslate"><span class="pre">if-else</span></code>
operators more flexible <a class="footnote-reference brackets" href="#id12" id="id3">[6]</a> without introducing any new syntax, so Ill be
writing that up as another possible alternative to <a class="pep reference internal" href="../pep-0505/" title="PEP 505 None-aware operators">PEP 505</a>.</p>
</section>
<section id="relationship-with-other-peps">
<h2><a class="toc-backref" href="#relationship-with-other-peps" role="doc-backlink">Relationship with other PEPs</a></h2>
<p>While this PEP was inspired by and builds on Mark Haases excellent work in
putting together <a class="pep reference internal" href="../pep-0505/" title="PEP 505 None-aware operators">PEP 505</a>, it ultimately competes with that PEP due to
significant differences in the specifics of the proposed syntax and semantics
for the feature.</p>
<p>It also presents a different perspective on the rationale for the change by
focusing on the benefits to existing Python users as the typical demands of
application and service development activities are genuinely changing. It
isnt an accident that similar features are now appearing in multiple
programming languages, and while its a good idea for us to learn from how other
language designers are handling the problem, precedents being set elsewhere
are more relevant to <em>how</em> we would go about tackling this problem than they
are to whether or not we think its a problem we should address in the first
place.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<section id="existence-checking-expressions">
<h3><a class="toc-backref" href="#existence-checking-expressions" role="doc-backlink">Existence checking expressions</a></h3>
<p>An increasingly common requirement in modern software development is the need
to work with “semi-structured data”: data where the structure of the data is
known in advance, but pieces of it may be missing at runtime, and the software
manipulating that data is expected to degrade gracefully (e.g. by omitting
results that depend on the missing data) rather than failing outright.</p>
<p>Some particularly common cases where this issue arises are:</p>
<ul class="simple">
<li>handling optional application configuration settings and function parameters</li>
<li>handling external service failures in distributed systems</li>
<li>handling data sets that include some partial records</li>
</ul>
<p>It is the latter two cases that are the primary motivation for this PEP - while
needing to deal with optional configuration settings and parameters is a design
requirement at least as old as Python itself, the rise of public cloud
infrastructure, the development of software systems as collaborative networks
of distributed services, and the availability of large public and private data
sets for analysis means that the ability to degrade operations gracefully in
the face of partial service failures or partial data availability is becoming
an essential feature of modern programming environments.</p>
<p>At the moment, writing such software in Python can be genuinely awkward, as
your code ends up littered with expressions like:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value1</span> <span class="pre">=</span> <span class="pre">expr1.field.of.interest</span> <span class="pre">if</span> <span class="pre">expr1</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span> <span class="pre">else</span> <span class="pre">None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">value2</span> <span class="pre">=</span> <span class="pre">expr2[&quot;field&quot;][&quot;of&quot;][&quot;interest&quot;]</span> <span class="pre">if</span> <span class="pre">expr2</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span> <span class="pre">else</span> <span class="pre">None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">value3</span> <span class="pre">=</span> <span class="pre">expr3</span> <span class="pre">if</span> <span class="pre">expr3</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span> <span class="pre">else</span> <span class="pre">expr4</span> <span class="pre">if</span> <span class="pre">expr4</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span> <span class="pre">else</span> <span class="pre">expr5</span></code></li>
</ul>
<p>If these are only occasional, then expanding out to full statement forms may
help improve readability, but if you have 4 or 5 of them in a row (which is a
fairly common situation in data transformation pipelines), then replacing them
with 16 or 20 lines of conditional logic really doesnt help matters.</p>
<p>Expanding the three examples above that way hopefully helps illustrate that:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">expr1</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">value1</span> <span class="o">=</span> <span class="n">expr1</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">of</span><span class="o">.</span><span class="n">interest</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">value1</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">expr2</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">value2</span> <span class="o">=</span> <span class="n">expr2</span><span class="p">[</span><span class="s2">&quot;field&quot;</span><span class="p">][</span><span class="s2">&quot;of&quot;</span><span class="p">][</span><span class="s2">&quot;interest&quot;</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">value2</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">expr3</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">value3</span> <span class="o">=</span> <span class="n">expr3</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="n">expr4</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">value3</span> <span class="o">=</span> <span class="n">expr4</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">value3</span> <span class="o">=</span> <span class="n">expr5</span>
</pre></div>
</div>
<p>The combined impact of the proposals in this PEP is to allow the above sample
expressions to instead be written as:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value1</span> <span class="pre">=</span> <span class="pre">expr1?.field.of.interest</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">value2</span> <span class="pre">=</span> <span class="pre">expr2?[&quot;field&quot;][&quot;of&quot;][&quot;interest&quot;]</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">value3</span> <span class="pre">=</span> <span class="pre">expr3</span> <span class="pre">?else</span> <span class="pre">expr4</span> <span class="pre">?else</span> <span class="pre">expr5</span></code></li>
</ul>
<p>In these forms, almost all of the information presented to the reader is
immediately relevant to the question “What does this code do?”, while the
boilerplate code to handle missing data by passing it through to the output
or falling back to an alternative input, has shrunk to two uses of the <code class="docutils literal notranslate"><span class="pre">?</span></code>
symbol and two uses of the <code class="docutils literal notranslate"><span class="pre">?else</span></code> keyword.</p>
<p>In the first two examples, the 31 character boilerplate clause
<code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">exprN</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span> <span class="pre">else</span> <span class="pre">None</span></code> (minimally 27 characters for a single letter
variable name) has been replaced by a single <code class="docutils literal notranslate"><span class="pre">?</span></code> character, substantially
improving the signal-to-pattern-noise ratio of the lines (especially if it
encourages the use of more meaningful variable and field names rather than
making them shorter purely for the sake of expression brevity).</p>
<p>In the last example, two instances of the 21 character boilerplate,
<code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">exprN</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span></code> (minimally 17 characters) are replaced with single
characters, again substantially improving the signal-to-pattern-noise ratio.</p>
<p>Furthermore, each of our 5 “subexpressions of potential interest” is included
exactly once, rather than 4 of them needing to be duplicated or pulled out
to a named variable in order to first check if they exist.</p>
<p>The existence checking precondition operator is mainly defined to provide a
clear conceptual basis for the existence checking attribute access and
subscripting operators:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">obj?.attr</span></code> is roughly equivalent to <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">?then</span> <span class="pre">obj.attr</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">obj?[expr]</span></code> is roughly equivalent to <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">?then</span> <span class="pre">obj[expr]</span></code></li>
</ul>
<p>The main semantic difference between the shorthand forms and their expanded
equivalents is that the common subexpression to the left of the existence
checking operator is evaluated only once in the shorthand form (similar to
the benefit offered by augmented assignment statements).</p>
</section>
<section id="existence-checking-assignment">
<h3><a class="toc-backref" href="#existence-checking-assignment" role="doc-backlink">Existence checking assignment</a></h3>
<p>Existence-checking assignment is proposed as a relatively straightforward
expansion of the concepts in this PEP to also cover the common configuration
handling idiom:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">value</span> <span class="pre">if</span> <span class="pre">value</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span> <span class="pre">else</span> <span class="pre">expensive_default()</span></code></li>
</ul>
<p>by allowing that to instead be abbreviated as:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">?=</span> <span class="pre">expensive_default()</span></code></li>
</ul>
<p>This is mainly beneficial when the target is a subscript operation or
subattribute, as even without this specific change, the PEP would still
permit this idiom to be updated to:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">value</span> <span class="pre">?else</span> <span class="pre">expensive_default()</span></code></li>
</ul>
<p>The main argument <em>against</em> adding this form is that its arguably ambiguous
and could mean either:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">value</span> <span class="pre">?else</span> <span class="pre">expensive_default()</span></code>; or</li>
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">value</span> <span class="pre">?then</span> <span class="pre">value.subfield.of.interest</span></code></li>
</ul>
<p>The second form isnt at all useful, but if this concern was deemed significant
enough to address while still keeping the augmented assignment feature,
the full keyword could be included in the syntax:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">?else=</span> <span class="pre">expensive_default()</span></code></li>
</ul>
<p>Alternatively, augmented assignment could just be dropped from the current
proposal entirely and potentially reconsidered at a later date.</p>
</section>
<section id="existence-checking-protocol">
<h3><a class="toc-backref" href="#existence-checking-protocol" role="doc-backlink">Existence checking protocol</a></h3>
<p>The existence checking protocol is including in this proposal primarily to
allow for proxy objects (e.g. local representations of remote resources) and
mock objects used in testing to correctly indicate non-existence of target
resources, even though the proxy or mock object itself is not None.</p>
<p>However, with that protocol defined, it then seems natural to expand it to
provide a type independent way of checking for <code class="docutils literal notranslate"><span class="pre">NaN</span></code> values in numeric types
- at the moment you need to be aware of the exact data type youre working with
(e.g. builtin floats, builtin complex numbers, the decimal module) and use the
appropriate operation (e.g. <code class="docutils literal notranslate"><span class="pre">math.isnan</span></code>, <code class="docutils literal notranslate"><span class="pre">cmath.isnan</span></code>,
<code class="docutils literal notranslate"><span class="pre">decimal.getcontext().is_nan()</span></code>, respectively)</p>
<p>Similarly, it seems reasonable to declare that the other placeholder builtin
singletons, <code class="docutils literal notranslate"><span class="pre">Ellipsis</span></code> and <code class="docutils literal notranslate"><span class="pre">NotImplemented</span></code>, also qualify as objects that
represent the absence of data more so than they represent data.</p>
</section>
<section id="proposed-symbolic-notation">
<h3><a class="toc-backref" href="#proposed-symbolic-notation" role="doc-backlink">Proposed symbolic notation</a></h3>
<p>Python has historically only had one kind of implied boolean context: truth
checking, which can be invoked directly via the <code class="docutils literal notranslate"><span class="pre">bool()</span></code> builtin. As this PEP
proposes a new kind of control flow operation based on existence checking rather
than truth checking, it is considered valuable to have a reminder directly
in the code when existence checking is being used rather than truth checking.</p>
<p>The mathematical symbol for existence assertions is U+2203 THERE EXISTS: <code class="docutils literal notranslate"><span class="pre"></span></code></p>
<p>Accordingly, one possible approach to the syntactic additions proposed in this
PEP would be to use that already defined mathematical notation:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">∃then</span> <span class="pre">expr2</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">∃else</span> <span class="pre">expr2</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">obj∃.attr</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">obj∃[expr]</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">target</span> <span class="pre">∃=</span> <span class="pre">expr</span></code></li>
</ul>
<p>However, there are two major problems with that approach, one practical, and
one pedagogical.</p>
<p>The practical problem is the usual one that most keyboards dont offer any easy
way of entering mathematical symbols other than those used in basic arithmetic
(even the symbols appearing in this PEP were ultimately copied &amp; pasted
from <a class="footnote-reference brackets" href="#id9" id="id4">[3]</a> rather than being entered directly).</p>
<p>The pedagogical problem is that the symbols for existence assertions (<code class="docutils literal notranslate"><span class="pre"></span></code>)
and universal assertions (<code class="docutils literal notranslate"><span class="pre"></span></code>) arent going to be familiar to most people
the way basic arithmetic operators are, so we wouldnt actually be making the
proposed syntax easier to understand by adopting <code class="docutils literal notranslate"><span class="pre"></span></code>.</p>
<p>By contrast, <code class="docutils literal notranslate"><span class="pre">?</span></code> is one of the few remaining unused ASCII punctuation
characters in Pythons syntax, making it available as a candidate syntactic
marker for “this control flow operation is based on an existence check, not a
truth check”.</p>
<p>Taking that path would also have the advantage of aligning Pythons syntax
with corresponding syntax in other languages that offer similar features.</p>
<p>Drawing from the existing summary in <a class="pep reference internal" href="../pep-0505/" title="PEP 505 None-aware operators">PEP 505</a> and the Wikipedia articles on
the “safe navigation operator <a class="footnote-reference brackets" href="#id7" id="id5">[1]</a> and the “null coalescing operator” <a class="footnote-reference brackets" href="#id8" id="id6">[2]</a>,
we see:</p>
<ul class="simple">
<li>The <code class="docutils literal notranslate"><span class="pre">?.</span></code> existence checking attribute access syntax precisely aligns with:<ul>
<li>the “safe navigation” attribute access operator in C# (<code class="docutils literal notranslate"><span class="pre">?.</span></code>)</li>
<li>the “optional chaining” operator in Swift (<code class="docutils literal notranslate"><span class="pre">?.</span></code>)</li>
<li>the “safe navigation” attribute access operator in Groovy (<code class="docutils literal notranslate"><span class="pre">?.</span></code>)</li>
<li>the “conditional member access” operator in Dart (<code class="docutils literal notranslate"><span class="pre">?.</span></code>)</li>
</ul>
</li>
<li>The <code class="docutils literal notranslate"><span class="pre">?[]</span></code> existence checking attribute access syntax precisely aligns with:<ul>
<li>the “safe navigation” subscript operator in C# (<code class="docutils literal notranslate"><span class="pre">?[]</span></code>)</li>
<li>the “optional subscript” operator in Swift (<code class="docutils literal notranslate"><span class="pre">?[].</span></code>)</li>
</ul>
</li>
<li>The <code class="docutils literal notranslate"><span class="pre">?else</span></code> existence checking fallback syntax semantically aligns with:<ul>
<li>the “null-coalescing” operator in C# (<code class="docutils literal notranslate"><span class="pre">??</span></code>)</li>
<li>the “null-coalescing” operator in PHP (<code class="docutils literal notranslate"><span class="pre">??</span></code>)</li>
<li>the “nil-coalescing” operator in Swift (<code class="docutils literal notranslate"><span class="pre">??</span></code>)</li>
</ul>
</li>
</ul>
<p>To be clear, these arent the only spelling of these operators used in other
languages, but theyre the most common ones, and the <code class="docutils literal notranslate"><span class="pre">?</span></code> symbol is the most
common syntactic marker by far (presumably prompted by the use of <code class="docutils literal notranslate"><span class="pre">?</span></code> to
introduce the “then” clause in C-style conditional expressions, which many
of these languages also offer).</p>
</section>
<section id="proposed-keywords">
<h3><a class="toc-backref" href="#proposed-keywords" role="doc-backlink">Proposed keywords</a></h3>
<p>Given the symbolic marker <code class="docutils literal notranslate"><span class="pre">?</span></code>, it would be syntactically unambiguous to spell
the existence checking precondition and fallback operations using the same
keywords as their truth checking counterparts:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">?and</span> <span class="pre">expr2</span></code> (instead of <code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">?then</span> <span class="pre">expr2</span></code>)</li>
<li><code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">?or</span> <span class="pre">expr2</span></code> (instead of <code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">?else</span> <span class="pre">expr2</span></code>)</li>
</ul>
<p>However, while syntactically unambiguous when written, this approach makes
the code incredibly hard to <em>pronounce</em> (Whats the pronunciation of “?”?) and
also hard to <em>describe</em> (given reused keywords, theres no obvious shorthand
terms for “existence checking precondition (?and)” and “existence checking
fallback (?or)” that would distinguish them from “logical conjunction (and)”
and “logical disjunction (or)”).</p>
<p>We could try to encourage folks to pronounce the <code class="docutils literal notranslate"><span class="pre">?</span></code> symbol as “exists”,
making the shorthand names the “exists-and expression” and the
“exists-or expression”, but thered be no way of guessing those names purely
from seeing them written in a piece of code.</p>
<p>Instead, this PEP takes advantage of the proposed symbolic syntax to introduce
a new keyword (<code class="docutils literal notranslate"><span class="pre">?then</span></code>) and borrow an existing one (<code class="docutils literal notranslate"><span class="pre">?else</span></code>) in a way
that allows people to refer to “then expressions” and “else expressions”
without ambiguity.</p>
<p>These keywords also align well with the conditional expressions that are
semantically equivalent to the proposed expressions.</p>
<p>For <code class="docutils literal notranslate"><span class="pre">?else</span></code> expressions, <code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">?else</span> <span class="pre">expr2</span></code> is equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_lhs_result</span> <span class="o">=</span> <span class="n">expr1</span>
<span class="n">_lhs_result</span> <span class="k">if</span> <span class="n">operator</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">_lhs_result</span><span class="p">)</span> <span class="k">else</span> <span class="n">expr2</span>
</pre></div>
</div>
<p>Here the parallel is clear, since the <code class="docutils literal notranslate"><span class="pre">else</span> <span class="pre">expr2</span></code> appears at the end of
both the abbreviated and expanded forms.</p>
<p>For <code class="docutils literal notranslate"><span class="pre">?then</span></code> expressions, <code class="docutils literal notranslate"><span class="pre">expr1</span> <span class="pre">?then</span> <span class="pre">expr2</span></code> is equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_lhs_result</span> <span class="o">=</span> <span class="n">expr1</span>
<span class="n">expr2</span> <span class="k">if</span> <span class="n">operator</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">_lhs_result</span><span class="p">)</span> <span class="k">else</span> <span class="n">_lhs_result</span>
</pre></div>
</div>
<p>Here the parallel isnt as immediately obvious due to Pythons traditionally
anonymous “then” clauses (introduced by <code class="docutils literal notranslate"><span class="pre">:</span></code> in <code class="docutils literal notranslate"><span class="pre">if</span></code> statements and suffixed
by <code class="docutils literal notranslate"><span class="pre">if</span></code> in conditional expressions), but its still reasonably clear as long
as youre already familiar with the “if-then-else” explanation of conditional
control flow.</p>
</section>
</section>
<section id="risks-and-concerns">
<h2><a class="toc-backref" href="#risks-and-concerns" role="doc-backlink">Risks and concerns</a></h2>
<section id="readability">
<h3><a class="toc-backref" href="#readability" role="doc-backlink">Readability</a></h3>
<p>Learning to read and write the new syntax effectively mainly requires
internalising two concepts:</p>
<ul class="simple">
<li>expressions containing <code class="docutils literal notranslate"><span class="pre">?</span></code> include an existence check and may short circuit</li>
<li>if <code class="docutils literal notranslate"><span class="pre">None</span></code> or another “non-existent” value is an expected input, and the
correct handling is to propagate that to the result, then the existence
checking operators are likely what you want</li>
</ul>
<p>Currently, these concepts arent explicitly represented at the language level,
so its a matter of learning to recognise and use the various idiomatic
patterns based on conditional expressions and statements.</p>
</section>
<section id="magic-syntax">
<h3><a class="toc-backref" href="#magic-syntax" role="doc-backlink">Magic syntax</a></h3>
<p>Theres nothing about <code class="docutils literal notranslate"><span class="pre">?</span></code> as a syntactic element that inherently suggests
<code class="docutils literal notranslate"><span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span></code> or <code class="docutils literal notranslate"><span class="pre">operator.exists</span></code>. The main current use of <code class="docutils literal notranslate"><span class="pre">?</span></code> as a
symbol in Python code is as a trailing suffix in IPython environments to
request help information for the result of the preceding expression.</p>
<p>However, the notion of existence checking really does benefit from a pervasive
visual marker that distinguishes it from truth checking, and that calls for
a single-character symbolic syntax if were going to do it at all.</p>
</section>
<section id="conceptual-complexity">
<h3><a class="toc-backref" href="#conceptual-complexity" role="doc-backlink">Conceptual complexity</a></h3>
<p>This proposal takes the currently ad hoc and informal concept of “existence
checking” and elevates it to the status of being a syntactic language feature
with a clearly defined operator protocol.</p>
<p>In many ways, this should actually <em>reduce</em> the overall conceptual complexity
of the language, as many more expectations will map correctly between truth
checking with <code class="docutils literal notranslate"><span class="pre">bool(expr)</span></code> and existence checking with
<code class="docutils literal notranslate"><span class="pre">operator.exists(expr)</span></code> than currently map between truth checking and
existence checking with <code class="docutils literal notranslate"><span class="pre">expr</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span></code> (or <code class="docutils literal notranslate"><span class="pre">expr</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">NotImplemented</span></code>
in the context of operand coercion, or the various NaN-checking operations
in mathematical libraries).</p>
<p>As a simple example of the new parallels introduced by this PEP, compare:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">all_are_true</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">bool</span><span class="p">,</span> <span class="n">iterable</span><span class="p">))</span>
<span class="n">at_least_one_is_true</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">bool</span><span class="p">,</span> <span class="n">iterable</span><span class="p">))</span>
<span class="n">all_exist</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="n">operator</span><span class="o">.</span><span class="n">exists</span><span class="p">,</span> <span class="n">iterable</span><span class="p">))</span>
<span class="n">at_least_one_exists</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="n">operator</span><span class="o">.</span><span class="n">exists</span><span class="p">,</span> <span class="n">iterable</span><span class="p">))</span>
</pre></div>
</div>
</section>
</section>
<section id="design-discussion">
<h2><a class="toc-backref" href="#design-discussion" role="doc-backlink">Design Discussion</a></h2>
<section id="subtleties-in-chaining-existence-checking-expressions">
<h3><a class="toc-backref" href="#subtleties-in-chaining-existence-checking-expressions" role="doc-backlink">Subtleties in chaining existence checking expressions</a></h3>
<p>Similar subtleties arise in chaining existence checking expressions as already
exist in chaining logical operators: the behaviour can be surprising if the
right hand side of one of the expressions in the chain itself returns a
value that doesnt exist.</p>
<p>As a result, <code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">arg1</span> <span class="pre">?then</span> <span class="pre">f(arg1)</span> <span class="pre">?else</span> <span class="pre">default()</span></code> would be dubious for
essentially the same reason that <code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">cond</span> <span class="pre">and</span> <span class="pre">expr1</span> <span class="pre">or</span> <span class="pre">expr2</span></code> is dubious:
the former will evaluate <code class="docutils literal notranslate"><span class="pre">default()</span></code> if <code class="docutils literal notranslate"><span class="pre">f(arg1)</span></code> returns <code class="docutils literal notranslate"><span class="pre">None</span></code>, just
as the latter will evaluate <code class="docutils literal notranslate"><span class="pre">expr2</span></code> if <code class="docutils literal notranslate"><span class="pre">expr1</span></code> evaluates to <code class="docutils literal notranslate"><span class="pre">False</span></code> in
a boolean context.</p>
</section>
<section id="ambiguous-interaction-with-conditional-expressions">
<h3><a class="toc-backref" href="#ambiguous-interaction-with-conditional-expressions" role="doc-backlink">Ambiguous interaction with conditional expressions</a></h3>
<p>In the proposal as currently written, the following is a syntax error:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">f(arg)</span> <span class="pre">if</span> <span class="pre">arg</span> <span class="pre">?else</span> <span class="pre">default</span></code></li>
</ul>
<p>While the following is a valid operation that checks a second condition if the
first doesnt exist rather than merely being false:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">expr1</span> <span class="pre">if</span> <span class="pre">cond1</span> <span class="pre">?else</span> <span class="pre">cond2</span> <span class="pre">else</span> <span class="pre">expr2</span></code></li>
</ul>
<p>The expression chaining problem described above means that the argument can be
made that the first operation should instead be equivalent to:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">f(arg)</span> <span class="pre">if</span> <span class="pre">operator.exists(arg)</span> <span class="pre">else</span> <span class="pre">default</span></code></li>
</ul>
<p>requiring the second to be written in the arguably clearer form:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">expr1</span> <span class="pre">if</span> <span class="pre">(cond1</span> <span class="pre">?else</span> <span class="pre">cond2)</span> <span class="pre">else</span> <span class="pre">expr2</span></code></li>
</ul>
<p>Alternatively, the first form could remain a syntax error, and the existence
checking symbol could instead be attached to the <code class="docutils literal notranslate"><span class="pre">if</span></code> keyword:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">expr1</span> <span class="pre">if?</span> <span class="pre">cond</span> <span class="pre">else</span> <span class="pre">expr2</span></code></li>
</ul>
</section>
<section id="existence-checking-in-other-truth-checking-contexts">
<h3><a class="toc-backref" href="#existence-checking-in-other-truth-checking-contexts" role="doc-backlink">Existence checking in other truth-checking contexts</a></h3>
<p>The truth-checking protocol is currently used in the following syntactic
constructs:</p>
<ul class="simple">
<li>logical conjunction (and-expressions)</li>
<li>logical disjunction (or-expressions)</li>
<li>conditional expressions (if-else expressions)</li>
<li>if statements</li>
<li>while loops</li>
<li>filter clauses in comprehensions and generator expressions</li>
</ul>
<p>In the current PEP, switching from truth-checking with <code class="docutils literal notranslate"><span class="pre">and</span></code> and <code class="docutils literal notranslate"><span class="pre">or</span></code> to
existence-checking is a matter of substituting in the new keywords, <code class="docutils literal notranslate"><span class="pre">?then</span></code>
and <code class="docutils literal notranslate"><span class="pre">?else</span></code> in the appropriate places.</p>
<p>For other truth-checking contexts, it proposes either importing and
using the <code class="docutils literal notranslate"><span class="pre">operator.exists</span></code> API, or else continuing with the current idiom
of checking specifically for <code class="docutils literal notranslate"><span class="pre">expr</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">None</span></code> (or the context appropriate
equivalent).</p>
<p>The simplest possible enhancement in that regard would be to elevate the
proposed <code class="docutils literal notranslate"><span class="pre">exists()</span></code> API from an operator module function to a new builtin
function.</p>
<p>Alternatively, the <code class="docutils literal notranslate"><span class="pre">?</span></code> existence checking symbol could be supported as a
modifier on the <code class="docutils literal notranslate"><span class="pre">if</span></code> and <code class="docutils literal notranslate"><span class="pre">while</span></code> keywords to indicate the use of an
existence check rather than a truth check.</p>
<p>However, it isnt at all clear that the potential consistency benefits gained
for either suggestion would justify the additional disruption, so theyve
currently been omitted from the proposal.</p>
</section>
<section id="defining-expected-invariant-relations-between-bool-and-exists">
<h3><a class="toc-backref" href="#defining-expected-invariant-relations-between-bool-and-exists" role="doc-backlink">Defining expected invariant relations between <code class="docutils literal notranslate"><span class="pre">__bool__</span></code> and <code class="docutils literal notranslate"><span class="pre">__exists__</span></code></a></h3>
<p>The PEP currently leaves the definition of <code class="docutils literal notranslate"><span class="pre">__bool__</span></code> on all existing types
unmodified, which ensures the entire proposal remains backwards compatible,
but results in the following cases where <code class="docutils literal notranslate"><span class="pre">bool(obj)</span></code> returns <code class="docutils literal notranslate"><span class="pre">True</span></code>, but
the proposed <code class="docutils literal notranslate"><span class="pre">operator.exists(obj)</span></code> would return <code class="docutils literal notranslate"><span class="pre">False</span></code>:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">NaN</span></code> values for <code class="docutils literal notranslate"><span class="pre">float</span></code>, <code class="docutils literal notranslate"><span class="pre">complex</span></code>, and <code class="docutils literal notranslate"><span class="pre">decimal.Decimal</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">Ellipsis</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">NotImplemented</span></code></li>
</ul>
<p>The main argument for potentially changing these is that it becomes easier to
reason about potential code behaviour if we have a recommended invariant in
place saying that values which indicate they dont exist in an existence
checking context should also report themselves as being <code class="docutils literal notranslate"><span class="pre">False</span></code> in a truth
checking context.</p>
<p>Failing to define such an invariant would lead to arguably odd outcomes like
<code class="docutils literal notranslate"><span class="pre">float(&quot;NaN&quot;)</span> <span class="pre">?else</span> <span class="pre">0.0</span></code> returning <code class="docutils literal notranslate"><span class="pre">0.0</span></code> while <code class="docutils literal notranslate"><span class="pre">float(&quot;NaN&quot;)</span> <span class="pre">or</span> <span class="pre">0.0</span></code>
returns <code class="docutils literal notranslate"><span class="pre">NaN</span></code>.</p>
</section>
</section>
<section id="limitations">
<h2><a class="toc-backref" href="#limitations" role="doc-backlink">Limitations</a></h2>
<section id="arbitrary-sentinel-objects">
<h3><a class="toc-backref" href="#arbitrary-sentinel-objects" role="doc-backlink">Arbitrary sentinel objects</a></h3>
<p>This proposal doesnt attempt to provide syntactic support for the “sentinel
object” idiom, where <code class="docutils literal notranslate"><span class="pre">None</span></code> is a permitted explicit value, so a
separate sentinel object is defined to indicate missing values:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_SENTINEL</span> <span class="o">=</span> <span class="nb">object</span><span class="p">()</span>
<span class="k">def</span><span class="w"> </span><span class="nf">f</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">_SENTINEL</span><span class="p">):</span>
<span class="k">return</span> <span class="n">obj</span> <span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">_SENTINEL</span> <span class="k">else</span> <span class="n">default_value</span><span class="p">()</span>
</pre></div>
</div>
<p>This could potentially be supported at the expense of making the existence
protocol definition significantly more complex, both to define and to use:</p>
<ul class="simple">
<li>at the Python layer, <code class="docutils literal notranslate"><span class="pre">operator.exists</span></code> and <code class="docutils literal notranslate"><span class="pre">__exists__</span></code> implementations
would return the empty tuple to indicate non-existence, and otherwise return
a singleton tuple containing a reference to the object to be used as the
result of the existence check</li>
<li>at the C layer, <code class="docutils literal notranslate"><span class="pre">tp_exists</span></code> implementations would return NULL to indicate
non-existence, and otherwise return a <code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*</span></code> pointer as the
result of the existence check</li>
</ul>
<p>Given that change, the sentinel object idiom could be rewritten as:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>class Maybe:
SENTINEL = object()
def __init__(self, value):
self._result = (value,) is value is not self.SENTINEL else ()
def __exists__(self):
return self._result
def f(obj=Maybe.SENTINEL):
return Maybe(obj) ?else default_value()
</pre></div>
</div>
<p>However, I dont think cases where the 3 proposed standard sentinel values (i.e.
<code class="docutils literal notranslate"><span class="pre">None</span></code>, <code class="docutils literal notranslate"><span class="pre">Ellipsis</span></code> and <code class="docutils literal notranslate"><span class="pre">NotImplemented</span></code>) cant be used are going to be
anywhere near common enough for the additional protocol complexity and the loss
of symmetry between <code class="docutils literal notranslate"><span class="pre">__bool__</span></code> and <code class="docutils literal notranslate"><span class="pre">__exists__</span></code> to be worth it.</p>
</section>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>The Abstract already gives the gist of the proposal and the Rationale gives
some specific examples. If theres enough interest in the basic idea, then a
full specification will need to provide a precise correspondence between the
proposed syntactic sugar and the underlying conditional expressions that is
sufficient to guide the creation of a reference implementation.</p>
<p>…TBD…</p>
</section>
<section id="implementation">
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
<p>As with <a class="pep reference internal" href="../pep-0505/" title="PEP 505 None-aware operators">PEP 505</a>, actual implementation has been deferred pending in-principle
interest in the idea of adding these operators - the implementation isnt
the hard part of these proposals, the hard part is deciding whether or not
this is a change where the long term benefits for new and existing Python users
outweigh the short term costs involved in the wider ecosystem (including
developers of other implementations, language curriculum developers, and
authors of other Python related educational material) adjusting to the change.</p>
<p>…TBD…</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id7" role="doc-footnote">
<dt class="label" id="id7">[<a href="#id5">1</a>]</dt>
<dd>Wikipedia: Safe navigation operator
(<a class="reference external" href="https://en.wikipedia.org/wiki/Safe_navigation_operator">https://en.wikipedia.org/wiki/Safe_navigation_operator</a>)</aside>
<aside class="footnote brackets" id="id8" role="doc-footnote">
<dt class="label" id="id8">[<a href="#id6">2</a>]</dt>
<dd>Wikipedia: Null coalescing operator
(<a class="reference external" href="https://en.wikipedia.org/wiki/Null_coalescing_operator">https://en.wikipedia.org/wiki/Null_coalescing_operator</a>)</aside>
<aside class="footnote brackets" id="id9" role="doc-footnote">
<dt class="label" id="id9">[<a href="#id4">3</a>]</dt>
<dd>FileFormat.info: Unicode Character THERE EXISTS (U+2203)
(<a class="reference external" href="http://www.fileformat.info/info/unicode/char/2203/index.htm">http://www.fileformat.info/info/unicode/char/2203/index.htm</a>)</aside>
<aside class="footnote brackets" id="id10" role="doc-footnote">
<dt class="label" id="id10">[<a href="#id1">4</a>]</dt>
<dd>python-ideas discussion thread
(<a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2016-October/043415.html">https://mail.python.org/pipermail/python-ideas/2016-October/043415.html</a>)</aside>
<aside class="footnote brackets" id="id11" role="doc-footnote">
<dt class="label" id="id11">[<a href="#id2">5</a>]</dt>
<dd>Steven DApranos critique of the proposal
(<a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2016-October/043453.html">https://mail.python.org/pipermail/python-ideas/2016-October/043453.html</a>)</aside>
<aside class="footnote brackets" id="id12" role="doc-footnote">
<dt class="label" id="id12">[<a href="#id3">6</a>]</dt>
<dd>Considering a link to the idea of overloadable Boolean operators
(<a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2016-October/043447.html">https://mail.python.org/pipermail/python-ideas/2016-October/043447.html</a>)</aside>
</aside>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain under the terms of the
CC0 1.0 license: <a class="reference external" href="https://creativecommons.org/publicdomain/zero/1.0/">https://creativecommons.org/publicdomain/zero/1.0/</a></p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0531.rst">https://github.com/python/peps/blob/main/peps/pep-0531.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0531.rst">2023-10-11 12:05:51 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#pep-withdrawal">PEP Withdrawal</a></li>
<li><a class="reference internal" href="#relationship-with-other-peps">Relationship with other PEPs</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#existence-checking-expressions">Existence checking expressions</a></li>
<li><a class="reference internal" href="#existence-checking-assignment">Existence checking assignment</a></li>
<li><a class="reference internal" href="#existence-checking-protocol">Existence checking protocol</a></li>
<li><a class="reference internal" href="#proposed-symbolic-notation">Proposed symbolic notation</a></li>
<li><a class="reference internal" href="#proposed-keywords">Proposed keywords</a></li>
</ul>
</li>
<li><a class="reference internal" href="#risks-and-concerns">Risks and concerns</a><ul>
<li><a class="reference internal" href="#readability">Readability</a></li>
<li><a class="reference internal" href="#magic-syntax">Magic syntax</a></li>
<li><a class="reference internal" href="#conceptual-complexity">Conceptual complexity</a></li>
</ul>
</li>
<li><a class="reference internal" href="#design-discussion">Design Discussion</a><ul>
<li><a class="reference internal" href="#subtleties-in-chaining-existence-checking-expressions">Subtleties in chaining existence checking expressions</a></li>
<li><a class="reference internal" href="#ambiguous-interaction-with-conditional-expressions">Ambiguous interaction with conditional expressions</a></li>
<li><a class="reference internal" href="#existence-checking-in-other-truth-checking-contexts">Existence checking in other truth-checking contexts</a></li>
<li><a class="reference internal" href="#defining-expected-invariant-relations-between-bool-and-exists">Defining expected invariant relations between <code class="docutils literal notranslate"><span class="pre">__bool__</span></code> and <code class="docutils literal notranslate"><span class="pre">__exists__</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#limitations">Limitations</a><ul>
<li><a class="reference internal" href="#arbitrary-sentinel-objects">Arbitrary sentinel objects</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0531.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>