<p dir="ltr">On Oct 28, 2016 3:30 AM, "Nick Coghlan" <<a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>> wrote:<br>
> *snip*<br>
><br>
> 1. Do we collectively agree that "existence checking" is a useful<br>
> general concept that exists in software development and is distinct<br>
> from the concept of "truth checking"?</p>
<p dir="ltr">I'd hope so!</p>
<p dir="ltr">> 2. Do we collectively agree that the Python ecosystem would benefit<br>
> from an existence checking protocol that permits generalisation of<br>
> algorithms (especially short circuiting ones) across different "data<br>
> missing" indicators, including those defined in the language<br>
> definition, the standard library, and custom user code?</p>
<p dir="ltr">I {%think_string if think_string is not None else 'think'%} so.</p>
<p dir="ltr">> *snip*<br>
> 4. Do we collectively agree that "?then" and "?else" would be<br>
> reasonable spellings for such operators?</p>
<p dir="ltr">Personally, I find that kind of ugly. What's wrong with just ? instead of ?else?</p>
<p dir="ltr">> 5a. Do we collectively agree that "access this attribute only if the<br>
> object exists" would be a particularly common use case for such<br>
> operators?</p>
<p dir="ltr">Pretty sure I've done this like a zillion times.</p>
<p dir="ltr">> 5b. Do we collectively agree that "access this subscript only if the<br>
> object exists" would be a particularly common use case for such<br>
> operators?</p>
<p dir="ltr">I haven't really ever had to do this exactly, but it makes sense.</p>
<p dir="ltr">> 5c. Do we collectively agree that "bind this value to this target only<br>
> if the value currently bound to the target nominally doesn't exist"<br>
> would be a particularly common use case for such operators?</p>
<p dir="ltr">Yes. I see stuff like this a lot:</p>
<p dir="ltr">if x is not None:<br>
x = []</p>
<p dir="ltr">> 6a. Do we collectively agree that 'obj?.attr' would be a reasonable<br>
> spelling for "access this attribute only if the object exists"?<br>
> 6b. Do we collectively agree that 'obj?[expr]' would be a reasonable<br>
> spelling for "access this subscript only if the object exists"?<br>
> 6c. Do we collectively agree that 'target ?= expr' would be a<br>
> reasonable spelling for "bind this value to this target only if the<br>
> value currently bound to the target nominally doesn't exist"?<br>
></p>
<p dir="ltr">' '.join(['Yes!']*3)</p>
<p dir="ltr">> To be clear, this would be a *really* big addition to the language<br>
> that would have significant long term ramifications for how the<br>
> language gets taught to new developers.<br>
><br>
> At the same time, asking whether or not an object represents an<br>
> absence of data rather than the truth of a proposition seems to me<br>
> like a sufficiently common problem in a wide enough variety of domains<br>
> that it may be worth elevating to the level of giving it dedicated<br>
> syntactic support.<br>
><br>
> Regards,<br>
> Nick.<br>
><br>
> Rendered HTML version: <a href="https://www.python.org/dev/peps/pep-0531/">https://www.python.org/dev/peps/pep-0531/</a><br>
> ===============================<br>
><br>
> PEP: 531<br>
> Title: Existence checking operators<br>
> Version: $Revision$<br>
> Last-Modified: $Date$<br>
> Author: Nick Coghlan <<a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>><br>
> Status: Draft<br>
> Type: Standards Track<br>
> Content-Type: text/x-rst<br>
> Created: 25-Oct-2016<br>
> Python-Version: 3.7<br>
> Post-History: 28-Oct-2016<br>
><br>
> Abstract<br>
> ========<br>
><br>
> Inspired by PEP 505 and the related discussions, this PEP proposes the addition<br>
> of two new control flow operators to Python:<br>
><br>
> * Existence-checking precondition ("exists-then"): ``expr1 ?then expr2``<br>
> * Existence-checking fallback ("exists-else"): ``expr1 ?else expr2``<br>
><br>
> as well as the following abbreviations for common existence checking<br>
> expressions and statements:<br>
><br>
> * Existence-checking attribute access:<br>
> ``obj?.attr`` (for ``obj ?then obj.attr``)<br>
> * Existence-checking subscripting:<br>
> ``obj?[expr]`` (for ``obj ?then obj[expr]``)<br>
> * Existence-checking assignment:<br>
> ``value ?= expr`` (for ``value = value ?else expr``)<br>
><br>
> The common ``?`` symbol in these new operator definitions indicates that they<br>
> use a new "existence checking" protocol rather than the established<br>
> truth-checking protocol used by if statements, while loops, comprehensions,<br>
> generator expressions, conditional expressions, logical conjunction, and<br>
> logical disjunction.<br>
><br>
> This new protocol would be made available as ``operator.exists``, with the<br>
> following characteristics:<br>
><br>
> * types can define a new ``__exists__`` magic method (Python) or<br>
> ``tp_exists`` slot (C) to override the default behaviour. This optional<br>
> method has the same signature and possible return values as ``__bool__``.<br>
> * ``operator.exists(None)`` returns ``False``<br>
> * ``operator.exists(NotImplemented)`` returns ``False``<br>
> * ``operator.exists(Ellipsis)`` returns ``False``<br>
> * ``float``, ``complex`` and ``decimal.Decimal`` will override the existence<br>
> check such that ``NaN`` values return ``False`` and other values (including<br>
> zero values) return ``True``<br>
> * for any other type, ``operator.exists(obj)`` returns True by default. Most<br>
> importantly, values that evaluate to False in a truth checking context<br>
> (zeroes, empty containers) will still evaluate to True in an existence<br>
> checking context<br>
><br>
><br>
> Relationship with other PEPs<br>
> ============================<br>
><br>
> While this PEP was inspired by and builds on Mark Haase's excellent work in<br>
> putting together PEP 505, it ultimately competes with that PEP due to<br>
> significant differences in the specifics of the proposed syntax and semantics<br>
> for the feature.<br>
><br>
> It also presents a different perspective on the rationale for the change by<br>
> focusing on the benefits to existing Python users as the typical demands of<br>
> application and service development activities are genuinely changing. It<br>
> isn't an accident that similar features are now appearing in multiple<br>
> programming languages, and while it's a good idea for us to learn from how other<br>
> language designers are handling the problem, precedents being set elsewhere<br>
> are more relevant to *how* we would go about tackling this problem than they<br>
> are to whether or not we think it's a problem we should address in the first<br>
> place.<br>
><br>
><br>
> Rationale<br>
> =========<br>
><br>
> Existence checking expressions<br>
> ------------------------------<br>
><br>
> An increasingly common requirement in modern software development is the need<br>
> to work with "semi-structured data": data where the structure of the data is<br>
> known in advance, but pieces of it may be missing at runtime, and the software<br>
> manipulating that data is expected to degrade gracefully (e.g. by omitting<br>
> results that depend on the missing data) rather than failing outright.<br>
><br>
> Some particularly common cases where this issue arises are:<br>
><br>
> * handling optional application configuration settings and function parameters<br>
> * handling external service failures in distributed systems<br>
> * handling data sets that include some partial records<br>
><br>
> It is the latter two cases that are the primary motivation for this PEP - while<br>
> needing to deal with optional configuration settings and parameters is a design<br>
> requirement at least as old as Python itself, the rise of public cloud<br>
> infrastructure, the development of software systems as collaborative networks<br>
> of distributed services, and the availability of large public and private data<br>
> sets for analysis means that the ability to degrade operations gracefully in<br>
> the face of partial service failures or partial data availability is becoming<br>
> an essential feature of modern programming environments.<br>
><br>
> At the moment, writing such software in Python can be genuinely awkward, as<br>
> your code ends up littered with expressions like:<br>
><br>
> * ``value1 = expr1.field.of.interest if expr1 is not None else None``<br>
> * ``value2 = expr2["field"]["of"]["interest"] if expr2 is not None else None``<br>
> * ``value3 = expr3 if expr3 is not None else expr4 if expr4 is not<br>
> None else expr5``<br>
><br>
> If these are only occasional, then expanding out to full statement forms may<br>
> help improve readability, but if you have 4 or 5 of them in a row (which is a<br>
> fairly common situation in data transformation pipelines), then replacing them<br>
> with 16 or 20 lines of conditional logic really doesn't help matters.<br>
><br>
> Expanding the three examples above that way hopefully helps illustrate that::<br>
><br>
> _expr1 = expr1<br>
> if _expr1 is not None:<br>
> value1 = _expr1.field.of.interest<br>
> else:<br>
> value1 = None<br>
> _expr2 = expr2<br>
> if _expr2 is not None:<br>
> value2 = _expr2["field"]["of"]["interest"]<br>
> else:<br>
> value2 = None<br>
> _expr3 = expr3<br>
> if _expr3 is not None:<br>
> value3 = _expr3<br>
> else:<br>
> _expr4 = expr4<br>
> if _expr4 is not None:<br>
> value3 = _expr4<br>
> else:<br>
> value3 = expr5<br>
><br>
> The combined impact of the proposals in this PEP is to allow the above sample<br>
> expressions to instead be written as:<br>
><br>
> * ``value1 = expr1?.field.of.interest``<br>
> * ``value2 = expr2?["field"]["of"]["interest"]``<br>
> * ``value3 = expr3 ?else expr4 ?else expr5``<br>
><br>
> In these forms, almost all of the information presented to the reader is<br>
> immediately relevant to the question "What does this code do?", while the<br>
> boilerplate code to handle missing data by passing it through to the output<br>
> or falling back to an alternative input, has shrunk to two uses of the ``?``<br>
> symbol and two uses of the ``?else`` keyword.<br>
><br>
> In the first two examples, the 31 character boilerplate clause<br>
> `` if exprN is not None else None`` (minimally 27 characters for a single letter<br>
> variable name) has been replaced by a single ``?`` character, substantially<br>
> improving the signal-to-pattern-noise ratio of the lines (especially if it<br>
> encourages the use of more meaningful variable and field names rather than<br>
> making them shorter purely for the sake of expression brevity).<br>
><br>
> In the last example, two instances of the 21 character boilerplate,<br>
> `` if exprN is not None`` (minimally 17 characters) are replaced with single<br>
> characters, again substantially improving the signal-to-pattern-noise ratio.<br>
><br>
> Furthermore, each of our 5 "subexpressions of potential interest" is included<br>
> exactly once, rather than 4 of them needing to be duplicated or pulled out<br>
> to a named variable in order to first check if they exist.<br>
><br>
> The existence checking precondition operator is mainly defined to provide a<br>
> clear conceptual basis for the existence checking attribute access and<br>
> subscripting operators:<br>
><br>
> * ``obj?.attr`` is roughly equivalent to ``obj ?then obj.attr``<br>
> * ``obj?[expr]``is roughly equivalent to ``obj ?then obj[expr]``<br>
><br>
> The main semantic difference between the shorthand forms and their expanded<br>
> equivalents is that the common subexpression to the left of the existence<br>
> checking operator is evaluated only once in the shorthand form (similar to<br>
> the benefit offered by augmented assignment statements).<br>
><br>
><br>
> Existence checking assignment<br>
> -----------------------------<br>
><br>
> Existence-checking assignment is proposed as a relatively straightforward<br>
> expansion of the concepts in this PEP to also cover the common configuration<br>
> handling idiom:<br>
><br>
> * ``value = value if value is not None else expensive_default()``<br>
><br>
> by allowing that to instead be abbreviated as:<br>
><br>
> * ``value ?= expensive_default()``<br>
><br>
> This is mainly beneficial when the target is a subscript operation or<br>
> subattribute, as even without this specific change, the PEP would still<br>
> permit this idiom to be updated to:<br>
><br>
> * ``value = value ?else expensive_default()``<br>
><br>
> The main argument *against* adding this form is that it's arguably ambiguous<br>
> and could mean either:<br>
><br>
> * ``value = value ?else expensive_default()``; or<br>
> * ``value = value ?then value.subfield.of.interest``<br>
><br>
> The second form isn't at all useful, but if this concern was deemed significant<br>
> enough to address while still keeping the augmented assignment feature,<br>
> the full keyword could be included in the syntax:<br>
><br>
> * ``value ?else= expensive_default()``<br>
><br>
> Alternatively, augmented assignment could just be dropped from the current<br>
> proposal entirely and potentially reconsidered at a later date.<br>
><br>
><br>
> Existence checking protocol<br>
> ---------------------------<br>
><br>
> The existence checking protocol is including in this proposal primarily to<br>
> allow for proxy objects (e.g. local representations of remote resources) and<br>
> mock objects used in testing to correctly indicate non-existence of target<br>
> resources, even though the proxy or mock object itself is not None.<br>
><br>
> However, with that protocol defined, it then seems natural to expand it to<br>
> provide a type independent way of checking for ``NaN`` values in numeric types<br>
> - at the moment you need to be aware of the exact data type you're working with<br>
> (e.g. builtin floats, builtin complex numbers, the decimal module) and use the<br>
> appropriate operation (e.g. ``math.isnan``, ``cmath.isnan``,<br>
> ``decimal.getcontext().is_nan()``, respectively)<br>
><br>
> Similarly, it seems reasonable to declare that the other placeholder builtin<br>
> singletons, ``Ellipsis`` and ``NotImplemented``, also qualify as objects that<br>
> represent the absence of data moreso than they represent data.<br>
><br>
><br>
> Proposed symbolic notation<br>
> --------------------------<br>
><br>
> Python has historically only had one kind of implied boolean context: truth<br>
> checking, which can be invoked directly via the ``bool()`` builtin. As this PEP<br>
> proposes a new kind of control flow operation based on existence checking rather<br>
> than truth checking, it is considered valuable to have a reminder directly<br>
> in the code when existence checking is being used rather than truth checking.<br>
><br>
> The mathematical symbol for existence assertions is U+2203 'THERE EXISTS': ``∃``<br>
><br>
> Accordingly, one possible approach to the syntactic additions proposed in this<br>
> PEP would be to use that already defined mathematical notation:<br>
><br>
> * ``expr1 ∃then expr2``<br>
> * ``expr1 ∃else expr2``<br>
> * ``obj∃.attr``<br>
> * ``obj∃[expr]``<br>
> * ``target ∃= expr``<br>
><br>
> However, there are two major problems with that approach, one practical, and<br>
> one pedagogical.<br>
><br>
> The practical problem is the usual one that most keyboards don't offer any easy<br>
> way of entering mathematical symbols other than those used in basic arithmetic<br>
> (even the symbols appearing in this PEP were ultimately copied & pasted<br>
> from [3]_ rather than being entered directly).<br>
><br>
> The pedagogical problem is that the symbols for existence assertions (``∃``)<br>
> and universal assertions (``∀``) aren't going to be familiar to most people<br>
> the way basic arithmetic operators are, so we wouldn't actually be making the<br>
> proposed syntax easier to understand by adopting ``∃``.<br>
><br>
> By contrast, ``?`` is one of the few remaining unused ASCII punctuation<br>
> characters in Python's syntax, making it available as a candidate syntactic<br>
> marker for "this control flow operation is based on an existence check, not a<br>
> truth check".<br>
><br>
> Taking that path would also have the advantage of aligning Python's syntax<br>
> with corresponding syntax in other languages that offer similar features.<br>
><br>
> Drawing from the existing summary in PEP 505 and the Wikipedia articles on<br>
> the "safe navigation operator [1]_ and the "null coalescing operator" [2]_,<br>
> we see:<br>
><br>
> * The ``?.`` existence checking attribute access syntax precisely aligns with:<br>
><br>
> * the "safe navigation" attribute access operator in C# (``?.``)<br>
> * the "optional chaining" operator in Swift (``?.``)<br>
> * the "safe navigation" attribute access operator in Groovy (``?.``)<br>
> * the "conditional member access" operator in Dart (``?.``)<br>
><br>
> * The ``?[]`` existence checking attribute access syntax precisely aligns with:<br>
><br>
> * the "safe navigation" subscript operator in C# (``?[]``)<br>
> * the "optional subscript" operator in Swift (``?[].``)<br>
><br>
> * The ``?else`` existence checking fallback syntax semantically aligns with:<br>
><br>
> * the "null-coalescing" operator in C# (``??``)<br>
> * the "null-coalescing" operator in PHP (``??``)<br>
> * the "nil-coalescing" operator in Swift (``??``)<br>
><br>
> To be clear, these aren't the only spelling of these operators used in other<br>
> languages, but they're the most common ones, and the ``?`` symbol is the most<br>
> common syntactic marker by far (presumably prompted by the use of ``?`` to<br>
> introduce the "then" clause in C-style conditional expressions, which many<br>
> of these languages also offer).<br>
><br>
><br>
> Proposed keywords<br>
> -----------------<br>
><br>
> Given the symbolic marker ``?``, it would be syntactically unambiguous to spell<br>
> the existence checking precondition and fallback operations using the same<br>
> keywords as their truth checking counterparts:<br>
><br>
> * ``expr1 ?and expr2`` (instead of ``expr1 ?then expr2``)<br>
> * ``expr1 ?or expr2`` (instead of ``expr1 ?else expr2``)<br>
><br>
> However, while syntactically unambiguous when written, this approach makes<br>
> the code incredibly hard to *pronounce* (What's the pronunciation of "?"?) and<br>
> also hard to *describe* (given reused keywords, there's no obvious shorthand<br>
> terms for "existence checking precondition (?and)" and "existence checking<br>
> fallback (?or)" that would distinguish them from "logical conjunction (and)"<br>
> and "logical disjunction (or)").<br>
><br>
> We could try to encourage folks to pronounce the ``?`` symbol as "exists",<br>
> making the shorthand names the "exists-and expression" and the<br>
> "exists-or expression", but there'd be no way of guessing those names purely<br>
> from seeing them written in a piece of code.<br>
><br>
> Instead, this PEP takes advantage of the proposed symbolic syntax to introduce<br>
> a new keyword (``?then``) and borrow an existing one (``?else``) in a way<br>
> that allows people to refer to "then expressions" and "else expressions"<br>
> without ambiguity.<br>
><br>
> These keywords also align well with the conditional expressions that are<br>
> semantically equivalent to the proposed expressions.<br>
><br>
> For ``?else`` expressions, ``expr1 ?else expr2`` is equivalent to::<br>
><br>
> _lhs_result = expr1<br>
> _lhs_result if operator.exists(_lhs_result) else expr2<br>
><br>
> Here the parallel is clear, since the ``else expr2`` appears at the end of<br>
> both the abbreviated and expanded forms.<br>
><br>
> For ``?then`` expressions, ``expr1 ?then expr2`` is equivalent to::<br>
><br>
> _lhs_result = expr1<br>
> expr2 if operator.exists(_lhs_result) else _lhs_result<br>
><br>
> Here the parallel isn't as immediately obvious due to Python's traditionally<br>
> anonymous "then" clauses (introduced by ``:`` in ``if`` statements and suffixed<br>
> by ``if`` in conditional expressions), but it's still reasonably clear as long<br>
> as you're already familiar with the "if-then-else" explanation of conditional<br>
> control flow.<br>
><br>
><br>
> Risks and concerns<br>
> ==================<br>
><br>
> Readability<br>
> -----------<br>
><br>
> Learning to read and write the new syntax effectively mainly requires<br>
> internalising two concepts:<br>
><br>
> * expressions containing ``?`` include an existence check and may short circuit<br>
> * if ``None`` or another "non-existent" value is an expected input, and the<br>
> correct handling is to propagate that to the result, then the existence<br>
> checking operators are likely what you want<br>
><br>
> Currently, these concepts aren't explicitly represented at the language level,<br>
> so it's a matter of learning to recognise and use the various idiomatic<br>
> patterns based on conditional expressions and statements.<br>
><br>
><br>
> Magic syntax<br>
> ------------<br>
><br>
> There's nothing about ``?`` as a syntactic element that inherently suggests<br>
> ``is not None`` or ``operator.exists``. The main current use of ``?`` as a<br>
> symbol in Python code is as a trailing suffix in IPython environments to<br>
> request help information for the result of the preceding expression.<br>
><br>
> However, the notion of existence checking really does benefit from a pervasive<br>
> visual marker that distinguishes it from truth checking, and that calls for<br>
> a single-character symbolic syntax if we're going to do it at all.<br>
><br>
><br>
> Conceptual complexity<br>
> ---------------------<br>
><br>
> This proposal takes the currently ad hoc and informal concept of "existence<br>
> checking" and elevates it to the status of being a syntactic language feature<br>
> with a clearly defined operator protocol.<br>
><br>
> In many ways, this should actually *reduce* the overall conceptual complexity<br>
> of the language, as many more expectations will map correctly between truth<br>
> checking with ``bool(expr)`` and existence checking with<br>
> ``operator.exists(expr)`` than currently map between truth checking and<br>
> existence checking with ``expr is not None`` (or ``expr is not NotImplemented``<br>
> in the context of operand coercion, or the various NaN-checking operations<br>
> in mathematical libraries).<br>
><br>
> As a simple example of the new parallels introduced by this PEP, compare::<br>
><br>
> all_are_true = all(map(bool, iterable))<br>
> at_least_one_is_true = any(map(bool, iterable))<br>
> all_exist = all(map(operator.exists, iterable))<br>
> at_least_one_exists = any(map(operator.exists, iterable))<br>
><br>
><br>
> Design Discussion<br>
> =================<br>
><br>
> Subtleties in chaining existence checking expressions<br>
> -----------------------------------------------------<br>
><br>
> Similar subtleties arise in chaining existence checking expressions as already<br>
> exist in chaining logical operators: the behaviour can be surprising if the<br>
> right hand side of one of the expressions in the chain itself returns a<br>
> value that doesn't exist.<br>
><br>
> As a result, ``value = arg1 ?then f(arg1) ?else default()`` would be dubious for<br>
> essentially the same reason that ``value = cond and expr1 or expr2`` is dubious:<br>
> the former will evaluate ``default()`` if ``f(arg1)`` returns ``None``, just<br>
> as the latter will evaluate ``expr2`` if ``expr1`` evaluates to ``False`` in<br>
> a boolean context.<br>
><br>
><br>
> Ambiguous interaction with conditional expressions<br>
> --------------------------------------------------<br>
><br>
> In the proposal as currently written, the following is a syntax error:<br>
><br>
> * ``value = f(arg) if arg ?else default``<br>
><br>
> While the following is a valid operation that checks a second condition if the<br>
> first doesn't exist rather than merely being false:<br>
><br>
> * ``value = expr1 if cond1 ?else cond2 else expr2``<br>
><br>
> The expression chaining problem described above means that the argument can be<br>
> made that the first operation should instead be equivalent to:<br>
><br>
> * ``value = f(arg) if operator.exists(arg) else default``<br>
><br>
> requiring the second to be written in the arguably clearer form:<br>
><br>
> * ``value = expr1 if (cond1 ?else cond2) else expr2``<br>
><br>
> Alternatively, the first form could remain a syntax error, and the existence<br>
> checking symbol could instead be attached to the ``if`` keyword:<br>
><br>
> * ``value = expr1 if? cond else expr2``<br>
><br>
><br>
> Existence checking in other truth-checking contexts<br>
> ---------------------------------------------------<br>
><br>
> The truth-checking protocol is currently used in the following syntactic<br>
> constructs:<br>
><br>
> * logical conjunction (and-expressions)<br>
> * logical disjunction (or-expressions)<br>
> * conditional expressions (if-else expressions)<br>
> * if statements<br>
> * while loops<br>
> * filter clauses in comprehensions and generator expressions<br>
><br>
> In the current PEP, switching from truth-checking with ``and`` and ``or`` to<br>
> existence-checking is a matter of substituting in the new keywords, ``?then``<br>
> and ``?else`` in the appropriate places.<br>
><br>
> For other truth-checking contexts, it proposes either importing and<br>
> using the ``operator.exists`` API, or else continuing with the current idiom<br>
> of checking specifically for ``expr is not None`` (or the context appropriate<br>
> equivalent).<br>
><br>
> The simplest possible enhancement in that regard would be to elevate the<br>
> proposed ``exists()`` API from an operator module function to a new builtin<br>
> function.<br>
><br>
> Alternatively, the ``?`` existence checking symbol could be supported as a<br>
> modifier on the ``if`` and ``while`` keywords to indicate the use of an<br>
> existence check rather than a truth check.<br>
><br>
> However, it isn't at all clear that the potential consistency benefits gained<br>
> for either suggestion would justify the additional disruption, so they've<br>
> currently been omitted from the proposal.<br>
><br>
><br>
> Defining expected invariant relations between ``__bool__`` and ``__exists__``<br>
> -----------------------------------------------------------------------------<br>
><br>
> The PEP currently leaves the definition of ``__bool__`` on all existing types<br>
> unmodified, which ensures the entire proposal remains backwards compatible,<br>
> but results in the following cases where ``bool(obj)`` returns ``True``, but<br>
> the proposed ``operator.exists(obj)`` would return ``False``:<br>
><br>
> * ``NaN`` values for ``float``, ``complex``, and ``decimal.Decimal``<br>
> * ``Ellipsis``<br>
> * ``NotImplemented``<br>
><br>
> The main argument for potentially changing these is that it becomes easier to<br>
> reason about potential code behaviour if we have a recommended invariant in<br>
> place saying that values which indicate they don't exist in an existence<br>
> checking context should also report themselves as being ``False`` in a truth<br>
> checking context.<br>
><br>
> Failing to define such an invariant would lead to arguably odd outcomes like<br>
> ``float("NaN") ?else 0.0`` returning ``0.0`` while ``float("NaN") or 0.0``<br>
> returns ``NaN``.<br>
><br>
><br>
> Limitations<br>
> ===========<br>
><br>
> Arbitrary sentinel objects<br>
> --------------------------<br>
><br>
> This proposal doesn't attempt to provide syntactic support for the "sentinel<br>
> object" idiom, where ``None`` is a permitted explicit value, so a<br>
> separate sentinel object is defined to indicate missing values::<br>
><br>
> _SENTINEL = object()<br>
> def f(obj=_SENTINEL):<br>
> return obj if obj is not _SENTINEL else default_value()<br>
><br>
> This could potentially be supported at the expense of making the existence<br>
> protocol definition significantly more complex, both to define and to use:<br>
><br>
> * at the Python layer, ``operator.exists`` and ``__exists__`` implementations<br>
> would return the empty tuple to indicate non-existence, and otherwise return<br>
> a singleton tuple containing a reference to the object to be used as the<br>
> result of the existence check<br>
> * at the C layer, ``tp_exists`` implementations would return NULL to indicate<br>
> non-existence, and otherwise return a `PyObject *` pointer as the<br>
> result of the existence check<br>
><br>
> Given that change, the sentinel object idiom could be rewritten as::<br>
><br>
> class Maybe:<br>
> SENTINEL = object()<br>
> def __init__(self, value):<br>
> self._result = (value,) is value is not self.SENTINEL else ()<br>
> def __exists__(self):<br>
> return self._result<br>
><br>
> def f(obj=Maybe.SENTINEL):<br>
> return Maybe(obj) ?else default_value()<br>
><br>
> However, I don't think cases where the 3 proposed standard sentinel values (i.e.<br>
> ``None``, ``Ellipsis`` and ``NotImplemented``) can't be used are going to be<br>
> anywhere near common enough for the additional protocol complexity and the loss<br>
> of symmetry between ``__bool__`` and ``__exists__`` to be worth it.<br>
><br>
><br>
> Specification<br>
> =============<br>
><br>
> The Abstract already gives the gist of the proposal and the Rationale gives<br>
> some specific examples. If there's enough interest in the basic idea, then a<br>
> full specification will need to provide a precise correspondence between the<br>
> proposed syntactic sugar and the underlying conditional expressions that is<br>
> sufficient to guide the creation of a reference implementation.<br>
><br>
> ...TBD...<br>
><br>
><br>
> Implementation<br>
> ==============<br>
><br>
> As with PEP 505, actual implementation has been deferred pending in-principle<br>
> interest in the idea of adding these operators - the implementation isn't<br>
> the hard part of these proposals, the hard part is deciding whether or not<br>
> this is a change where the long term benefits for new and existing Python users<br>
> outweigh the short term costs involved in the wider ecosystem (including<br>
> developers of other implementations, language curriculum developers, and<br>
> authors of other Python related educational material) adjusting to the change.<br>
><br>
> ...TBD...<br>
><br>
><br>
> References<br>
> ==========<br>
><br>
> .. [1] Wikipedia: Safe navigation operator<br>
> (<a href="https://en.wikipedia.org/wiki/Safe_navigation_operator">https://en.wikipedia.org/wiki/Safe_navigation_operator</a>)<br>
><br>
> .. [2] Wikipedia: Null coalescing operator<br>
> (<a href="https://en.wikipedia.org/wiki/Null_coalescing_operator">https://en.wikipedia.org/wiki/Null_coalescing_operator</a>)<br>
><br>
> .. [3] FileFormat.info: Unicode Character 'THERE EXISTS' (U+2203)<br>
> (<a href="http://www.fileformat.info/info/unicode/char/2203/index.htm">http://www.fileformat.info/info/unicode/char/2203/index.htm</a>)<br>
><br>
><br>
> Copyright<br>
> =========<br>
><br>
> This document has been placed in the public domain under the terms of the<br>
> CC0 1.0 license: <a href="https://creativecommons.org/publicdomain/zero/1.0/">https://creativecommons.org/publicdomain/zero/1.0/</a><br>
><br>
><br>
> ..<br>
> Local Variables:<br>
> mode: indented-text<br>
> indent-tabs-mode: nil<br>
> sentence-end-double-space: t<br>
> fill-column: 70<br>
> coding: utf-8<br>
> End:<br>
><br>
><br>
><br>
><br>
> --<br>
> Nick Coghlan | <a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a> | Brisbane, Australia<br>
> _______________________________________________<br>
> Python-ideas mailing list<br>
> <a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-ideas">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
> Code of Conduct: <a href="http://python.org/psf/codeofconduct/">http://python.org/psf/codeofconduct/</a><br><br></p>
<p dir="ltr">--<br>
Ryan (ライアン)<br>
[ERROR]: Your autotools build scripts are 200 lines longer than your program. Something’s wrong.<br>
<a href="http://kirbyfan64.github.io/">http://kirbyfan64.github.io/</a></p>