Python from Wise Guy's Viewpoint

Marcin 'Qrczak' Kowalczyk qrczak at knm.org.pl
Mon Oct 20 08:46:16 EDT 2003


Followup-To: comp.lang.misc

On Mon, 20 Oct 2003 13:06:08 +0200, Joachim Durchholz wrote:

>>>The longer answer: Multimethods have modularity issues (if whatever
>>>domain they're dispatching on can be extended by independent developers:
>>>different developers may extend the dispatch domain of a function in
>>>different directions, and leave undefined combinations;
>> 
>> This doesn't matter until you provide an equally powerful mechanism
>> which fixes that. Which is it?
> 
> I don't think there is a satisfactory one. It's a fundamental problem:
> if two people who don't know of each other can extend the same thing
> (framework, base class, whatever) in different directions, who's
> responsible for writing the code needed to combine these extensions?

Indeed. I wouldn't thus blame the language mechanism.

> 1. Let the system decide. Technically feasible for base classes (in the
> form of priorisation rules for multimethods), technically infeasible for
> frameworks. The problem here is that the system doesn't (usually) have
> enough information to reliably make the correct decision.

Sometimes the programmer can write enough default specializations that it
can be freely extended. Example: drawing shapes on devices. If every shape
is convertible to Bezier curves, and every device is capable of drawing
Bezier curves, then the most generic specialization, for arbitrary shape
and arbitrary device, will call 'draw' again with the shape converted to
Bezier curves.

The potential of multimethods is used: particular shapes have specialized
implementations for particular devices (drawing text is usually better
done more directly than through curves), separate modules can provide
additional shapes and additional devices. Yet it is safe and modular, as
long as people agree who provides a particular specialization.

It's easy to agree with a certain restriction: the specialization is
provided either by the module providing the shape or by module providing
the device. In practice the restriction doesn't have to be always followed
- it's enough that the module providing the specialization is known to all
people who might want to write their own, so I wouldn't advocate enforcing
the restriction on the language level.

I would favor multimethods even if they provided only solutions extensible
in one dimension, since they are nicer than having to enumerate all cases
in one place. Better to have a partially extensible mechanism than nothing.
Here it is extensible.

> 2. Let the system declare an error if the glue code isn't there.
> Effectively prohibits all forms of dynamic code loading. Can create risks
> in project management (unexpected error messages during code integration
> near a project deadline - yuck). Creates a temptation to hack the glue
> code up, by people who don't know the details of the two modules involved.

It would be interesting to let the system find the coverage of multimethods,
but without making it an error if not all combinations are covered. It's
useful to be able to test an incomplete program.

There is no definite answer for what kind of errors should prevent running
the program. It's similar to static/dynamic typing, or being able to
compile calls to unimplemented functions or not.

Even if the system shows that all combinations are covered, it doesn't
imply that they do the right thing. It's analogous to failing to override
a method in class-based OOP - the system doesn't know if the superclass
implementation is appropriate for the subclass. So you can't completely
rely on detection of such errors anyway.

> 3. Disallow extending in multiple directions. In other words, no
> multimethods, and live with the asymmetry. Too restricted to be
> comfortable with.

I agree.

> 4. As (3), but allow multiple extensions if they are contained within the
> same module. I.e. allow multiple dispatch within an "arithmetics" module
> that defines the classes Integer, Real, Complex, etc. etc., but don't
> allow additional multiple dispatch outside the module. (Single dispatch
> would, of course, be OK.)

For me it's still too restricted. It's a useful guideline to follow but
it should not be a hard requirement.

> 5. As (3), but require manual intervention. IOW let the two authors who
> did the orthogonal extensions know about each other, and have each module
> refer to the other, and each module carry the glue code required to
> combine with the other.

The glue code might reside in yet another module, especially if each of
the modules makes sense without the other (so it might better not depend
on it). Again, for me it's just a guideline - if one of the modules can
ensure that it's composable with the other, it's a good idea to change it -
but I would like to be able to provide the glue code elsewhere to make
them working in my program which uses both, and remove it once the modules
include the glue code themselves.

> Actually, this is the practice for various open source projects. For
> example, authors of MTAs, mail servers etc. cooperate to set standards. Of
> course, if the authors aren't interested in cooperating, this doesn't work
> well either.

The modules might also be a part of one program, where it's relatively
easy to make them cooperate. Inability to cope with some uses is generally
not a sufficient reason to reject a language mechamism which also has well
working uses.

> 6. Don't use dynamic dispatch, use parametric polymorphism (or whatever
> your language offers for that purpose, be it "generics" or "templates").

I think it can rarely solve the same problem. C++ templates (which can
use overloaded operations, i.e. with implementation dependent on type
parameters) help only in statically resolvable cases. Fully parametric
polymorphism doesn't seem to help at all even in these cases (equality,
arithmetic).

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak at knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/





More information about the Python-list mailing list