[Python-ideas] PEP 505: None-aware operators
Thomas Jollans
tjol at tjol.eu
Mon Jul 23 18:22:05 EDT 2018
On 18/07/18 19:43, Steve Dower wrote:
> When a ``None``-aware operator is present, the left-to-right evaluation
> may be
> short-circuited. For example, ``await a?.b(c).d?[e]`` is evaluated::
>
> _v = a
> if _v is not None:
> _v = _v.b
> _v = _v(c)
> _v = _v.d
> if _v is not None:
> _v = _v[e]
> await _v
## NB I only skimmed most of this thread after reading the PEP, so I ##
## apologize if this has been discussed before and I missed it. ##
I quite like the general idea, but I'm nervous about a rather
fundamental aspect: This adds a special case in which you can't add
parentheses to an expression involving a chain of operators to make
precedence and evaluation order clear.
To use your example,
a ?? 2 ** b ?? 3 === (a ?? 2) ** (b ?? 3) # fine
In the present day,
a or 2 + 3 * c() === a or (2 + (3 * (c())))
a.b(c).d[e] === (((a.b)(c)).d)[e] # silly, but true.
Short-circuiting doesn't break this. With and and or, the expression
that's short-circuited away is a self-contained expression in imagined
(or actual) parentheses.
With this ?. operator, the chain a?.b(c).d?[e] can no longer be broken
into sub-expressions, but becomes one single, long, atomic expression,
just like a comparison chain. If I try:
(a?.b)(c).d?[e] # TypeError: 'NoneType' object is not callable
a?.(b(c).d?[e]) # SyntaxError, and illogical
Also, where does this end? if a is None, is (a?.b,c()) equal to None or
(None, c())? Presumably the latter because of operator precedence, but
still.
Is introducing the idea of an "attribute reference, call and
subscription" chain worth it?
This could be fixed by adding a maybe-call ?( operator, which would allow
a?.b?(C())?.d?[E()]
===
((((a?.b)
?( C() ))
?.d)
?[ E() ])
_v = a
_v = _v.b if _v is not None else None
_v = _v(C()) if _v is not None else None
_v = _v.d if _v is not None else None
_v = _v[E()] if _v is not None else None
with None falling all the way through, and the calls to C() and E()
being short-circuited out.
Of course you need either attribute-call-subscription chains or ‘?()’
maybe-calls for ‘?.’ to be worthwhile at all, since otherwise you can't
write None-aware method calls.
Aside: other languages cited
From a quick look at the C# docs linked in the PEP [1], I'm guessing
that C# allows A?.B?.C?.Do(E), but does not allow A?.B?.C.Do(E). Does
anybody know? Obviously method calls work differently in C# than in
Python.
Dart? I dunno. The docs aren't as thorough.
Am I missing something?
Cheers
Thomas
[1]
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators
More information about the Python-ideas
mailing list