@@ -455,17 +455,24 @@ is broken once a (soft-) keyword is reached.
455455Grouping
456456********
457457
458- Grouping is an implicit property of the `Short-circuiting `_ behavior.
459- If a group contains a non short-circuiting expression, i.e. one that
460- is not either a name, attribute access, subscript, their ``None ``-aware
461- counterparts or a call expression, the short-circuiting chain will be
462- broken. The rule of thumb still applies: short-circuiting is broken once
463- a (soft-) keyword is reached.
464-
465- In the example below the group contains a ``BoolOp `` (``or ``) expression
466- which breaks the short-circuiting chain into two: ``a.b?.c `` inside
467- the group which is evaluated first and ``(...).e?.func() `` on the
468- outside.
458+ Using ``?. `` and ``?[ ] `` inside groups is possible. Short-circuiting
459+ will be broken either by the rules laid out in the `Short-circuiting `_
460+ section or at the end of a group. For example the expression ``(a?.b).c ``
461+ will raise an ``AttributeError `` on ``.c `` if ``a = None ``. This is
462+ conceptually identical to extracting the group contents and storing the
463+ result in a temporary variable before substituting it back into the
464+ original expression.
465+
466+ ::
467+
468+ # (a?.b).c
469+
470+ _t = a?.b
471+ _t.c
472+
473+ Common use cases for ``None ``-aware access operators in groups are
474+ boolean or conditional expressions which can provide a fallback value
475+ in case the first part evaluates to ``None ``.
469476
470477::
471478
@@ -480,16 +487,6 @@ outside.
480487 # (...).e?.func()
481488 _t4.func() if ((_t4 := _t3.e) is not None) else None
482489
483- In contrast, the example below only consists of a name, one attribute
484- access and two ``None ``-aware attribute access expressions. As such the
485- grouping does not break the short-circuiting chain. The brackets can
486- safely be removed.
487-
488- ::
489-
490- # Trivial groups
491- (a?.b).c?.d == a?.b.c?.d
492-
493490Assignments
494491***********
495492
@@ -540,7 +537,9 @@ Two new AST nodes are added ``NoneAwareAttribute`` and ``NoneAwareSubscript``.
540537They are the counterparts to the existing ``Attribute `` and ``Subscript ``
541538nodes. Notably there is no ``expr_context `` attribute because the new nodes
542539do not support assignments themselves and thus the context will always be
543- ``Load ``.
540+ ``Load ``. Furthermore, an optional ``group `` attribute is added for all
541+ expression nodes. It is set to ``1 `` if the expression is the topmost
542+ node in a group, ``0 `` otherwise.
544543
545544::
546545
@@ -551,6 +550,9 @@ do not support assignments themselves and thus the context will always be
551550 | NoneAwareAttribute(expr value, identifier attr)
552551 | NoneAwareSubscript(expr value, expr slice)
553552
553+ attributes (int? group, int lineno, int col_offset,
554+ int? end_lineno, int? end_col_offset)
555+
554556Grammar changes
555557---------------
556558
@@ -924,40 +926,36 @@ for lists and tuples and as such would be a valuable addition to the
924926language itself, it doesn't remove the need for arbitrary objects which
925927implement a custom ``__getitem__ `` method.
926928
927- Limit scope of short-circuiting with grouping
928- ---------------------------------------------
929+ Ignore groups for short-circuiting
930+ ----------------------------------
931+
932+ An earlier version of this PEP suggested the short-circuiting
933+ behavior should be indifferent towards grouping. It was assumed that
934+ short-circuiting would be broken already for more complex group
935+ expressions like ``(a?.b or c).d `` by the behavior outline in the
936+ `Short-circuiting `_ section. While for simpler ones like ``(a?.b).c ``
937+ the grouping was considered trivial and the expression would be equal to
938+ ``a?.b.c ``. The advantage being that developers would not have to
939+ look for groupings when evaluating simpler expressions. As long as
940+ any ``None ``-aware access operator was used and the expression was not
941+ broken by a (soft-) keyword, it would return ``None `` instead of raising
942+ an ``AttributeError `` or ``TypeError ``.
943+
944+ This suggestion was rejected in favor of the specification outline in
945+ the `Grouping `_ section since it violates the substitution principle.
946+ An expression ``(a?.b).c `` should behave the same whether or not ``a?.b ``
947+ is written inline inside a group or defined as a separate variable.
929948
930- Some languages like JS [#js_short_circuiting ]_ and C# [#csharp ]_ limit the
931- scope of the `Short-circuiting `_ via explicit grouping::
949+ ::
932950
933- a = None
934- x = (a?.b).c
935- # ^^^^^^
936-
937- In the example above short-circuiting would be limited to just ``a?.b ``,
938- thus with ``a = None `` the expression would raise an ``AttributeError ``
939- instead of setting ``x `` to ``None ``.
940-
941- Even though other languages have implemented it that way, this kind of
942- explicit grouping for short-circuiting does have its disadvantages.
943- The ``None ``-aware access operators are explicitly designed to return
944- ``None `` at some point. Directly limiting the scope of the
945- short-circuiting behavior almost guarantees that the code will raise
946- an ``AttributeError `` or ``TypeError `` at some point. Type checkers
947- would also have to raise an error for trying to access an attribute
948- or subscript on an ``optional `` variable again.
949-
950- As such breaking the short-circuiting chain does only make sense if a
951- fallback value is provided at the same time. For example::
952-
953- (a?.b.c or fallback).e.func()
954-
955- In case it is known that ``a `` will always be a not ``None `` value,
956- and it is just still typed as optional, better options include adding
957- an ``assert a is not None `` or if it is ever proposed a ``Not-None ``
958- assertion operator ``a! `` (out of scope for this PEP). Developers also
959- always have the option of splitting the expression up again like they do
960- today.
951+ (a?.b).c
952+
953+ _t = a?.b
954+ _t.c
955+
956+ Furthermore, defining the short-circuiting behavior that way would have
957+ been a deviation from the already established behavior in
958+ languages like JS [#js_short_circuiting ]_ and C# [#csharp ]_.
961959
962960
963961Common objections
0 commit comments