[Python-3000] Adaptation [was:Re: Iterators for dict keys, values, and items == annoying :)]
Alex Martelli
aleaxit at gmail.com
Mon Apr 3 03:27:31 CEST 2006
On Apr 2, 2006, at 4:39 PM, Walter Dörwald wrote:
...
> Why not make the registry identical to the protocol? The protocol
> is just a convention anyway:
Yes, a 1<->1 relationship between registries and protocols makes the
'registryof' function I was talking about simpler, at least when it's
implemented as identity. What's the advantage of this approach,
compared to allowing protocols to be arbitrary hashable attributes?
The disadvantage, essentially, is that one gives up the degrees of
freedom implied by protocols being "just a convention": a protocol
must now (say) be a callable object exposing a register method (with
given signature and semantics).
I guess adopting that kind of constraint is OK, as long as the
constraint doesn't in any way interfere with whatever else Guido
wants to do with protocols and thus give him a reason to reject
adaptation. I guess I can see some potential for minor optimization:
a protocol that's written with some existing types already in mind
might use a subclass of your 'Adaptor', such as:
class FastTracker(Adaptor):
def __init__(self, types):
self.fastrack = set(types)
Adaptor.__init__(self)
def _anyof(self, types):
for t in types:
if t in self.fastrack: return True
return False
def register(self, adaptor, types):
if self._anyof(types):
# need better diagnostics here, of course
raise RegistrationError, "Cannot override identity-
adaptation"
return Adaptor.register(self, adaptor, types)
def __call__(self, obj, *a, **k):
if self._anyof(type(obj).__mro__):
if a or k:
raise ...some kind of diagnostics about a/k not
allowed here...
return obj
return Adaptor.__call__(self, obj, *a, **k)
I'm not sure the advantage is big enough to warrant all the
machinery, but I can't assert it isn't, either.
>> Isn't it just wonderful, how the foes of adaptation switch horses
>> on you? First they request a simple-as-dirt, bare-bones
>> "example system" -- then as soon as you provide one they come
>> back at you with all sort of "cruft" to be piled on top.
>
> I think you might be misinterpreting reactions. If the initial
> reaction was "I don't understand it. Nobody needs this." (at least
> that was my reaction), you're "strawman proposal" has put us past
> this. (At least you got two "I finally got it, this seems useful"
> from me and Brett.)
You're quite likely right, and I apologize for the misinterpretation;
I guess I may have misread Brett's desire to hammer adaptation's very
reason for being down to miniscule smithereens by having the
existence of some set of methods "imply" identity-adaptation, as a
subconscious desire to defend against the whole idea of adaptation in
the guise of sort-of-accepting it, for example.
> So now lets answer the questions: How do we implement adaption of
> subtypes? What is a protocol? How can we make registration as
> painless as possible? etc.
Looks like the "loop on __mro__" idea is sort of standard for the
first of these questions. As for "what is a protocol", I'd rather
minimize the machinery that goes with it, but I guess that's some
kind of holdover from the "strawman proposal"; if we're making
protocols into classes anyway, I'd like to provide them with a
check_compliance method, taking an object and an integer that
represents the amount of effort to be spent in the checking -- 0
meaning 'just check existence of methods', 1 meaning 'check methods'
signature compatibility too', 2 meaning 'check some semantics at a
level suitable for fast unit-tests', and so on up. The author of a
protocol doesn't have to do all that much (levels 0 and 1 can be
provided by helper functions/methods relying on the inspect module),
but he or she CAN make the protocol into "an executable
specification" at whatever level he or she desires. Other error
checking (e.g., against registration of multiple adapters for one
protocol/type pair) as well as some modest optimization (mostly of
adaptation, the frequent case) may also be warranted.
I'm not sure what's painful at all about registration -- at worst
it's one call per type/protocol pair, some refactoring such as yours
making it even slighter by allowing the registration of several pairs
in one call. Do you mean that people are so keen on declarative
styles that they'd crave, e.g., some special machinery such as
class Duck(object):
__implements__ = walk, talk, quack
...
(with the metaclass doing the registration calls, with identity
adaptation, under the cover for each protocol in __implements__),
prizing it highly over explicit:
class Duck(object):
...
adapt.register(Duck, (walk, talk, quack), identity)
or the loop or classdecorator version of the latter? Ah well, maybe,
but most of the discussion sort of smacks to me of AGNI and/or
premature optimization.
Could we agree that simplicity and even minimalism (with a side order
of future extensibility if/when warranted) are high on the list of
desired properties for a protocol adaptation mechanism? After all,
the more machinery, cruft, and black magic we pile on top of
adaptation's simple core ideas, the more likely the whole caboodle is
to provoke allergic reactions in anybody who's not being a part of
this discussion...
Alex
More information about the Python-3000
mailing list