Make consistent use of the term "implementation" versus "overload"

This commit is contained in:
Łukasz Langa 2013-05-27 14:23:30 +02:00
parent 7d207bc210
commit 620f079ec8
1 changed files with 41 additions and 31 deletions

View File

@ -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)
<function fun_num at 0x104319058>
>>> fun.dispatch(dict)
<function fun at 0x103fe4788>
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