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
49
pep-0622.rst
49
pep-0622.rst
|
@ -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
|
||||
----------------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue