This new protocol would be made available as operator.exists , with the following characteristics:

The common ? 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.

as well as the following abbreviations for common existence checking expressions and statements:

Inspired by PEP 505 and the related discussions, this PEP proposes the addition of two new control flow operators to Python:

However, the discussion of the proposal did prompt consideration of a potential protocol based approach to make the existing and , or and if-else operators more flexible [ 6 ] without introducing any new syntax, so I'll be writing that up as another possible alternative to PEP 505 .

With that core design concept invalidated, the proposal as a whole doesn't make sense, and it is accordingly withdrawn.

In mathematics, the value of NaN is that programmatically 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 NaN values.

Similarly, Ellipsis exists for multi-dimensional slicing support due to None already have another meaning in a slicing context (indicating the use of the default start or stop indices, or the default step size).

NotImplemented exists, for example, due to None being a potentially legitimate result from overloaded arithmetic operators and exception handling imposing too much runtime overhead to be useful for operand coercion.

Steven D'Aprano articulated the counter-argument well in [ 5 ], but the general idea is that when checking for "missing data" sentinels, we're almost always looking for a specific sentinel value, rather than any sentinel value.

While the answers to the first question were generally positive, it quickly became clear that the answer to the second question is "No".

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?

When posting this PEP for discussion on python-ideas [ 4 ], I asked reviewers to consider 3 high level design questions before moving on to considering the specifics of this particular syntactic proposal:

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 isn't an accident that similar features are now appearing in multiple programming languages, and while it's a good idea for us to learn from how other language designers are handling the problem, precedents being set elsewhere are more relevant to how we would go about tackling this problem than they are to whether or not we think it's a problem we should address in the first place.

While this PEP was inspired by and builds on Mark Haase's excellent work in putting together PEP 505 , it ultimately competes with that PEP due to significant differences in the specifics of the proposed syntax and semantics for the feature.

Existence checking expressions 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. Some particularly common cases where this issue arises are: handling optional application configuration settings and function parameters

handling external service failures in distributed systems

handling data sets that include some partial records 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. At the moment, writing such software in Python can be genuinely awkward, as your code ends up littered with expressions like: value1 = expr1.field.of.interest if expr1 is not None else None

value2 = expr2["field"]["of"]["interest"] if expr2 is not None else None

value3 = expr3 if expr3 is not None else expr4 if expr4 is not None else expr5 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 doesn't help matters. Expanding the three examples above that way hopefully helps illustrate that: if expr1 is not None: value1 = expr1.field.of.interest else: value1 = None if expr2 is not None: value2 = expr2["field"]["of"]["interest"] else: value2 = None if expr3 is not None: value3 = expr3 else: if expr4 is not None: value3 = expr4 else: value3 = expr5 The combined impact of the proposals in this PEP is to allow the above sample expressions to instead be written as: value1 = expr1?.field.of.interest

value2 = expr2?["field"]["of"]["interest"]

value3 = expr3 ?else expr4 ?else expr5 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 ? symbol and two uses of the ?else keyword. In the first two examples, the 31 character boilerplate clause if exprN is not None else None (minimally 27 characters for a single letter variable name) has been replaced by a single ? 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). In the last example, two instances of the 21 character boilerplate, if exprN is not None (minimally 17 characters) are replaced with single characters, again substantially improving the signal-to-pattern-noise ratio. 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. The existence checking precondition operator is mainly defined to provide a clear conceptual basis for the existence checking attribute access and subscripting operators: obj?.attr is roughly equivalent to obj ?then obj.attr

is roughly equivalent to obj?[expr] is roughly equivalent to obj ?then obj[expr] 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).

Existence checking assignment Existence-checking assignment is proposed as a relatively straightforward expansion of the concepts in this PEP to also cover the common configuration handling idiom: value = value if value is not None else expensive_default() by allowing that to instead be abbreviated as: value ?= expensive_default() 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: value = value ?else expensive_default() The main argument against adding this form is that it's arguably ambiguous and could mean either: value = value ?else expensive_default() ; or

; or value = value ?then value.subfield.of.interest The second form isn't 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: value ?else= expensive_default() Alternatively, augmented assignment could just be dropped from the current proposal entirely and potentially reconsidered at a later date.

Existence checking protocol 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. However, with that protocol defined, it then seems natural to expand it to provide a type independent way of checking for NaN values in numeric types - at the moment you need to be aware of the exact data type you're working with (e.g. builtin floats, builtin complex numbers, the decimal module) and use the appropriate operation (e.g. math.isnan , cmath.isnan , decimal.getcontext().is_nan() , respectively) Similarly, it seems reasonable to declare that the other placeholder builtin singletons, Ellipsis and NotImplemented , also qualify as objects that represent the absence of data moreso than they represent data.

Proposed symbolic notation Python has historically only had one kind of implied boolean context: truth checking, which can be invoked directly via the bool() 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. The mathematical symbol for existence assertions is U+2203 'THERE EXISTS': ∃ Accordingly, one possible approach to the syntactic additions proposed in this PEP would be to use that already defined mathematical notation: expr1 ∃then expr2

expr1 ∃else expr2

obj∃.attr

obj∃[expr]

target ∃= expr However, there are two major problems with that approach, one practical, and one pedagogical. The practical problem is the usual one that most keyboards don't 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 & pasted from rather than being entered directly). The pedagogical problem is that the symbols for existence assertions ( ∃ ) and universal assertions ( ∀ ) aren't going to be familiar to most people the way basic arithmetic operators are, so we wouldn't actually be making the proposed syntax easier to understand by adopting ∃ . By contrast, ? is one of the few remaining unused ASCII punctuation characters in Python's syntax, making it available as a candidate syntactic marker for "this control flow operation is based on an existence check, not a truth check". Taking that path would also have the advantage of aligning Python's syntax with corresponding syntax in other languages that offer similar features. Drawing from the existing summary in PEP 505 and the Wikipedia articles on the "safe navigation operator and the "null coalescing operator" , we see: The ?. existence checking attribute access syntax precisely aligns with: the "safe navigation" attribute access operator in C# ( ?. ) the "optional chaining" operator in Swift ( ?. ) the "safe navigation" attribute access operator in Groovy ( ?. ) the "conditional member access" operator in Dart ( ?. )

existence checking attribute access syntax precisely aligns with: The ?[] existence checking attribute access syntax precisely aligns with: the "safe navigation" subscript operator in C# ( ?[] ) the "optional subscript" operator in Swift ( ?[]. )

existence checking attribute access syntax precisely aligns with: The ?else existence checking fallback syntax semantically aligns with: the "null-coalescing" operator in C# ( ?? ) the "null-coalescing" operator in PHP ( ?? ) the "nil-coalescing" operator in Swift ( ?? )

existence checking fallback syntax semantically aligns with: To be clear, these aren't the only spelling of these operators used in other languages, but they're the most common ones, and the ? symbol is the most common syntactic marker by far (presumably prompted by the use of ? to introduce the "then" clause in C-style conditional expressions, which many of these languages also offer).