PEP 622: Added rejected ideas section comparing with traditional OOP (#1504)
Co-authored-by: Brandt Bucher <brandtbucher@gmail.com>
This commit is contained in:
parent
26ac4b3d3e
commit
382f0dfc7d
71
pep-0622.rst
71
pep-0622.rst
|
@ -202,7 +202,7 @@ separates alternative patterns (not unlike regular expressions or EBNF
|
|||
grammars), and ``_`` is a wildcard.
|
||||
|
||||
In some occasions, extraction of information is not as relevant as
|
||||
identifying structure. Take the following example from the
|
||||
identifying structure. Take the following example from the
|
||||
`Python standard library
|
||||
<https://github.com/python/cpython/blob/c4cacc8/Lib/lib2to3/fixer_util.py#L158>`_::
|
||||
|
||||
|
@ -297,11 +297,11 @@ functionality that is useful now but conservative. More patterns can be added
|
|||
later as this feature gets more widespread use. See the `rejected ideas`_
|
||||
and `deferred ideas`_ sections for more details.
|
||||
|
||||
The patterns listed here are described in more detail below, but summarized
|
||||
The patterns listed here are described in more detail below, but summarized
|
||||
together in this section for simplicity:
|
||||
|
||||
- A **literal pattern** is useful to filter constant values in a structure.
|
||||
It looks like a Python literal (including some values like ``True``,
|
||||
It looks like a Python literal (including some values like ``True``,
|
||||
``False`` and ``None``). It only matches objects equal to the literal, and
|
||||
never binds.
|
||||
- A **capture pattern** looks like ``x`` and is equivalent to an identical
|
||||
|
@ -309,12 +309,12 @@ together in this section for simplicity:
|
|||
with the given name.
|
||||
- The **wildcard pattern** is a single underscore: ``_``. It always matches,
|
||||
but does not capture any variable (which prevents interference with other
|
||||
uses for ``_`` and allows for some optimizations).
|
||||
uses for ``_`` and allows for some optimizations).
|
||||
- A **constant value pattern** works like the literal but for certain named
|
||||
constants. Note that it must be a qualified (dotted) name, given the possible
|
||||
ambiguity with a capture pattern. It looks like ``Color.RED`` and
|
||||
only matches values equal to the corresponding value. It never binds.
|
||||
- A **sequence pattern** looks like ``[a, *rest, b]`` and is similar to
|
||||
- A **sequence pattern** looks like ``[a, *rest, b]`` and is similar to
|
||||
a list unpacking. An important difference is that the elements nested
|
||||
within it can be any kind of patterns, not just names or sequences.
|
||||
It matches only sequences of appropriate length, as long as all the sub-patterns
|
||||
|
@ -526,7 +526,7 @@ the ``""`` case clause was taken::
|
|||
... # but works fine if greeting was not empty
|
||||
|
||||
While matching against each case clause, a name may be bound at most
|
||||
once, having two capture patterns with coinciding names is an error::
|
||||
once, having two capture patterns with coinciding names is an error::
|
||||
|
||||
match data:
|
||||
case [x, x]: # Error!
|
||||
|
@ -537,7 +537,7 @@ Also, ``[x, y] | Point(x, y)`` is a legal pattern because the two
|
|||
alternatives are never matched at the same time.
|
||||
|
||||
The single underscore (``_``) is not considered a ``NAME`` and treated specially
|
||||
as a `wildcard pattern`_.
|
||||
as a `wildcard pattern`_.
|
||||
|
||||
Reminder: ``None``, ``False`` and ``True`` are keywords denoting
|
||||
literals, not names.
|
||||
|
@ -603,8 +603,8 @@ Sequence Patterns
|
|||
Simplified syntax::
|
||||
|
||||
sequence_pattern:
|
||||
| '[' [values_pattern] ']'
|
||||
| '(' [value_pattern ',' [values pattern]] ')'
|
||||
| '[' [values_pattern] ']'
|
||||
| '(' [value_pattern ',' [values pattern]] ')'
|
||||
values_pattern: ','.value_pattern+ ','?
|
||||
value_pattern: '*' capture_pattern | pattern
|
||||
|
||||
|
@ -1315,6 +1315,55 @@ above illustrate this comparison well enough. For more real code examples
|
|||
and their translations see Ref. [7]_.
|
||||
|
||||
|
||||
Don't do this, use existing method dispatching mechanisms
|
||||
---------------------------------------------------------
|
||||
|
||||
We recognize that some of the use cases for the ``match`` statement overlap
|
||||
with what can be done with traditional object-oriented programming (OOP) design
|
||||
techniques using class inheritance. The ability to choose alternate
|
||||
behaviors based on testing the runtime type of a match subject might
|
||||
even seem heretical to strict OOP purists.
|
||||
|
||||
However, Python has always been a language that embraces a variety of
|
||||
programming styles and paradigms. Classic Python design idioms such as
|
||||
"duck"-typing go beyond the traditional OOP model.
|
||||
|
||||
We believe that there are important use cases where the use of ``match`` results
|
||||
in a cleaner and more maintainable architecture. These use cases tend to
|
||||
be characterized by a number of features:
|
||||
|
||||
* Algorithms which cut across traditional lines of data encapsulation. If an
|
||||
algorithm is processing heterogenous elements of different types (such as
|
||||
evaluating or transforming an abstract syntax tree, or doing algebraic
|
||||
manipulation of mathematical symbols), forcing the user to implement
|
||||
the algorithm as individual methods on each element type results in
|
||||
logic that is smeared across the entire codebase instead of being neatly
|
||||
localized in once place.
|
||||
* Program architectures where the set of possible data types is relatively
|
||||
stable, but there is an ever-expanding set of operations to be performed
|
||||
on those data types. Doing this in a strict OOP fashion requires constantly
|
||||
adding new methods to both the base class and subclasses to support the new
|
||||
methods, "polluting" the base class with lots of very specialized method
|
||||
definitions, and causing widespread disruption and churn in the code. By
|
||||
contrast, in a ``match``-based dispatch, adding a new behavior merely
|
||||
involves writing a new ``match`` statement.
|
||||
* OOP also does not handle dispatching based on the *shape* of an object, such
|
||||
as the length of a tuple, or the presence of an attribute -- instead any such
|
||||
dispatching decision must be encoded into the object's type. Shape-based
|
||||
dispatching is particularly interesting when it comes to handling "duck"-typed
|
||||
objects.
|
||||
|
||||
Where OOP is clearly superior is in the opposite case: where the set of possible
|
||||
operations is relatively stable and well-defined, but there is an ever-growing
|
||||
set of data types to operate on. A classic example of this is UI widget toolkits,
|
||||
where there is a fixed set of interaction types (repaint, mouse click, keypress,
|
||||
and so on), but the set of widget types is constantly expanding as developers
|
||||
invent new and creative user interaction styles. Adding a new kind of widget
|
||||
is a simple matter of writing a new subclass, whereas with a match-based approach
|
||||
you end up having to add a new case clause to many widespread match statements.
|
||||
We therefore don't recommend using ``match`` in such a situation.
|
||||
|
||||
|
||||
Allow more flexible assignment targets instead
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -1898,7 +1947,7 @@ Other pattern-based constructions
|
|||
---------------------------------
|
||||
|
||||
Many other languages supporting pattern-matching use it as a basis for multiple
|
||||
language constructs, including a matching operator, a generalized form
|
||||
language constructs, including a matching operator, a generalized form
|
||||
of assignment, a filter for loops, a method for synchronizing communication,
|
||||
or specialized if statements. Some of these were mentioned in the discussion
|
||||
of the first draft. Another question asked was why this particular form (joining
|
||||
|
@ -2093,7 +2142,7 @@ Version History
|
|||
- Drop ``ImpossibleMatchError`` exception
|
||||
- Drop leading dot for loads (moved to `deferred ideas`_)
|
||||
- Reworked the initial sections (everything before `syntax`_)
|
||||
- Added an overview of all the types of patterns before the
|
||||
- Added an overview of all the types of patterns before the
|
||||
detailed description
|
||||
- Added simplified syntax next to the description of each pattern
|
||||
- Separate description of the wildcard from capture patterns
|
||||
|
|
Loading…
Reference in New Issue