From 620f079ec865b02204779b43fc37a65ff797aeff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 27 May 2013 14:23:30 +0200 Subject: [PATCH] Make consistent use of the term "implementation" versus "overload" --- pep-0443.txt | 72 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt index 9fdde6786..d5f7712a7 100644 --- a/pep-0443.txt +++ b/pep-0443.txt @@ -19,10 +19,11 @@ This PEP proposes a new mechanism in the ``functools`` standard library module that provides a simple form of generic programming known as single-dispatch generic functions. -A **generic function** is composed of multiple functions sharing the -same name. Which form should be used during a call is determined by the -dispatch algorithm. When the implementation is chosen based on the type -of a single argument, this is known as **single dispatch**. +A **generic function** is composed of multiple functions implementing +the same operation for different types. Which implementation should be +used during a call is determined by the dispatch algorithm. When the +implementation is chosen based on the type of a single argument, this is +known as **single dispatch**. Rationale and Goals @@ -72,8 +73,9 @@ argument, create your function accordingly:: ... print(arg) To add overloaded implementations to the function, use the -``register()`` attribute of the generic function. It takes a type -parameter:: +``register()`` attribute of the generic function. It is a decorator, +taking a type parameter and decorating a function implementing the +operation for that type:: >>> @fun.register(int) ... def _(arg, verbose=False): @@ -110,7 +112,8 @@ each variant independently:: >>> fun_num is fun False -When called, the generic function dispatches on the first argument:: +When called, the generic function dispatches on the type of the first +argument:: >>> fun("Hello, world.") Hello, world. @@ -129,15 +132,17 @@ When called, the generic function dispatches on the first argument:: >>> fun(1.23) 0.615 -To get the implementation for a specific type, use the ``dispatch()`` -attribute:: +Where there is no registered implementation for a specific type, its +method resolution order is used to find a more generic implementation. +To check which implementation will the generic function choose for +a given type, use the ``dispatch()`` attribute:: >>> fun.dispatch(float) >>> fun.dispatch(dict) -To access all registered overloads, use the read-only ``registry`` +To access all registered implementations, use the read-only ``registry`` attribute:: >>> fun.registry.keys() @@ -180,9 +185,10 @@ method resultion order (MRO). ``@singledispatch`` removes special handling of old-style classes and Zope's ExtensionClasses. More importantly, it introduces support for Abstract Base Classes (ABC). -When a generic function overload is registered for an ABC, the dispatch -algorithm switches to a mode of MRO calculation for the provided -argument which includes the relevant ABCs. The algorithm is as follows:: +When a generic function implementation is registered for an ABC, the +dispatch algorithm switches to a mode of MRO calculation for the +provided argument which includes the relevant ABCs. The algorithm is as +follows:: def _compose_mro(cls, haystack): """Calculates the MRO for a given class `cls`, including relevant @@ -218,9 +224,10 @@ of, they are inserted in a predictable order:: While this mode of operation is significantly slower, all dispatch decisions are cached. The cache is invalidated on registering new -overloads on the generic function or when user code calls ``register()`` -on an ABC to register a new virtual subclass. In the latter case, it is -possible to create a situation with ambiguous dispatch, for instance:: +implementations on the generic function or when user code calls +``register()`` on an ABC to register a new virtual subclass. In the +latter case, it is possible to create a situation with ambiguous +dispatch, for instance:: >>> from collections import Iterable, Container >>> class P: @@ -274,24 +281,27 @@ Universal overloading does not equal *arbitrary* overloading, in the sense that we need not expect people to randomly redefine the behavior of existing functions in unpredictable ways. To the contrary, generic function usage in actual programs tends to follow very predictable -patterns and overloads are highly-discoverable in the common case. +patterns and registered implementations are highly-discoverable in the +common case. If a module is defining a new generic operation, it will usually also -define any required overloads for existing types in the same place. -Likewise, if a module is defining a new type, then it will usually -define overloads there for any generic functions that it knows or cares -about. As a result, the vast majority of overloads can be found adjacent -to either the function being overloaded, or to a newly-defined type for -which the overload is adding support. +define any required implementations for existing types in the same +place. Likewise, if a module is defining a new type, then it will +usually define implementations there for any generic functions that it +knows or cares about. As a result, the vast majority of registered +implementations can be found adjacent to either the function being +overloaded, or to a newly-defined type for which the implementation is +adding support. -It is only in rather infrequent cases that one will have overloads in -a module that contains neither the function nor the type(s) for which -the overload is added. In the absence of incompetence or deliberate -intention to be obscure, the few overloads that are not adjacent to the -relevant type(s) or function(s), will generally not need to be -understood or known about outside the scope where those overloads are -defined. (Except in the "support modules" case, where best practice -suggests naming them accordingly.) +It is only in rather infrequent cases that one will have implementations +registered in a module that contains neither the function nor the +type(s) for which the implementation is added. In the absence of +incompetence or deliberate intention to be obscure, the few +implementations that are not registered adjacent to the relevant type(s) +or function(s), will generally not need to be understood or known about +outside the scope where those implementations are defined. (Except in +the "support modules" case, where best practice suggests naming them +accordingly.) As mentioned earlier, single-dispatch generics are already prolific throughout the standard library. A clean, standard way of doing them