[Python-Dev] *Simpler* string substitutions

Alex Martelli aleax@aleax.it
Sat, 22 Jun 2002 09:58:14 +0200

On Friday 21 June 2002 11:39 pm, David Abrahams wrote:
> > That's point (e) in the Requirements of the PEP:
> >
> > """
> > e) When the context knows about the object and the protocol and
> >        knows how to adapt the object so that the required protocol is
> >        satisfied.  This could use an adapter registry or similar
> >        method.
> > """
> Oh, sorry I missed that.

Easy to miss because the PEP (I think) makes no further reference to
[e], not even to say it's not gonna address it directly.  I think the PEP
could be enhanced about this (as about the reference implementation's
buglet which I already remarked upon).

> I was thinking of the use of template specialization to describe the
> relationship of a type to a library, e.g. specialization of
> std::iterator_traits<libA::some_class> by libB, which makes
> libA::some_class available for use as an iterator with the standard library
> (assuming it has some appropriate interface).

That requires proper design for extensibility in advance -- the standard
library must have had the forethought to define, and use everywhere
appropriate, std::iterator_traits, AND libA must expose classes that
can be plugged into that "slot".

As I tried indicating, if you're willing to require design-in-advance for
such issues, PEP 246 (together with Python's general mechanisms)
already offer what you need.

Allow me to offer an analogy: a Ruby programmer complains to a
Python or C++ programmer "your language ain't flexible enough!  I
have a library X that supplies type X1 and a library Y that consumes
any type Y1 which exposes a method Y2 and I want to just add a
suitable Y2 to the existing X1 but Python/C++ doesn't let me modify
the existing type/class X1".
The Python or C++ programmer replies: "well INHERIT from X1
and add method Y2, that's easy".
The Ruby programmer retorts" "No use, library X does in umpteen
places a 'new X1();' [in C++ terms] so my subclassing won't be
picked up"
The Python or C++ programmer triumphantly concludes: "Ah that's
a design error in X, X should instead use a factory makeX1() and
let you override THAT to make your Y2-enriched X1 instead".

Yeah right.  That's like the airplane manufactures explaining away
most crashes as "pilot error".  Perrow's "Normal Accidents" (GREAT
book btw) is highly recommended reading, particularly to anybody
who still falls for that line.  *Humans are fallible* and most often in
quite predictable ways: a system that stresses humans just the wrong
way is gonna produce "pilot error" over and over AND over again.
Wishing for a better Human Being Release 2.0 is just silly.  Ain't
gonna come and we couldn't afford the upgrade fee if it did:-).

Yes, factories and such creational patterns ARE a better long-term
answer, BUT there's no denying that Ruby's ability to patch things
up with duct tape (while having its own costs, of course!-) can
be a short-term lifesaver.  "If God had WANTED us to get things
right the first time he wouldn't have created duct tape", after all:-).

End of analogy...

The way I read [e] is more demanding -- allowing some degree of
"impedance matching" WITHOUT requiring special forethought by
the designers of either library, beyond using adapt rather than
typetesting -- just some ingenuity on the third party's part.

> > Only Haskell's typeclass, AFAIK, has (among widely used languages and
> > objectmodels) a smooth way to allow noninvasive 3rd party post-facto
> > adaptation (and another couple of small gems too), but I guess it has an
> > easier life because it's compile-time rather than runtime.
> IIUC the same kind of thing can be implemented in C++ templates, if you
> know where to look. There's been a lot of discussion of how to build
> variant types lately.

I don't think you can do it without some degree of design forethought,
but admittedly I'm starting to get very slightly rusty (haven't designed a
dazzling new C++ template in almost six months, after all:-).