[Python-3000] Generic functions
Ian Bicking
ianb at colorstudy.com
Mon Apr 3 19:25:29 CEST 2006
As an alternative to adaptation, I'd like to propose generic functions.
I think they play much the same role, except they are much simpler to
use and think about.
Though RuleDispatch offers considerably more features through predicate
dispatch, it would probably be best to just consider type based
dispatch, as that's more equivalent to adaptation.
So, the copy_reg module is one example where adaptation has been
proposed. The idea is that you adapt an object to a pickleable object,
or something along those lines. It's a little vague, because while you
typically adapt an instance coming in, you "adapt" a string to a new
instance on the way out. Or, I dunno, it's not clear to me. In fact,
though that's the typical example, I'm going to bail on that because the
pickling protocol is an aside to this and too complex for me to digest
right now. pprint is a lot easier, and conveniently is much nicer with
generic functions than adaptation ;)
Anyway, pprint could work like:
class PrettyPrinter:
@generic
def pformat(self, object):
"""Return the pretty string representation of object"""
return repr(object)
# pformat is now "more" than just a function, it's a callable
# object that does type-based dispatch using an internal registery
# of implementations, with the implementation above as the fallback.
# It also now can be used as a decorator that registers implementations:
@PrettyPrinter.pformat.when(object=list)
def pformat_list(self, object):
s = '['
for item in object:
s += (' '*self.indent) + self.pformat(item) + ',\n'
return s + (' '*self.indent) + ']'
Some things to note:
* There's no interface created here. There's no hidden interface
lurking in the background either.
* It requires cooperation from the original function (pformat -- I'm
using "function" and "method" interchangably). It does not require any
cooperation from classes like list, similar to adaptation and dissimilar
to magic methods. Adaptation also requires cooperation from the caller,
as the adaptation would be applied inside pformat.
* The function is mostly self-describing. If it has certain return
values, then you state what those values are in documentation; there's
no need to be formal about it. In contrast you have to come up with a
whole collection of interfaces to start using adaptation.
* The function is the hub of all the registration, which seems very
natural, since you are extending the function.
* Like adaptation, you must import a module that defines extra
specializations of the generic function before those are active (just
like you have to import adapter declarations). This strikes me as a
significant problem. I assume ZCML addresses this, but I also assume
that's not a reasonable solution for core Python.
* Magic methods do *not* have this import problem, because once you have
an object you have all its methods, including magic methods.
RuleDispatch has a bunch more features than just simple type-based
generic functions. But I think that type-based generic functions would
be an easier or more comfortable place to start, and wouldn't preclude a
more featureful implementation later.
Type-based generic functions and adaptation are more-or-less equivalent.
That is, you can express one in terms of the other, at least
functionally if not syntactically. If you really wanted adaptation,
then the interface becomes a things-obeying-this-interface factory --
i.e., a generic function. Generic functions are similer to
multi-adaptaters, where you adapt a tuple of objects, similar to the
tuple of arguments to a function. This is technically like generic
functions, but syntactically rather awkward.
[Predicate-based dispatching goes considerably further, allowing real
duck typing, e.g., you could implement a pformat method for everything
that has an "__iter__" method and no "next" method (i.e., all iterables,
but not iterators which could lead to unintentionally consuming the
iterator).]
Anyway, I think generic functions are very compatible with Python syntax
and style, and Python's greater emphasis on what an object or function
can *do*, as opposed to what an object *is*, as well as the use of
functions instead of methods for many operations. People sometimes see
the use of functions instead of methods in Python as a weakness; I think
generic functions turns that into a real strength.
--
Ian Bicking / ianb at colorstudy.com / http://blog.ianbicking.org
More information about the Python-3000
mailing list