[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