[Python-Dev] PEP 246, redux

Alex Martelli aleax at aleax.it
Tue Jan 11 11:59:06 CET 2005


On 2005 Jan 11, at 11:01, Alex Martelli wrote:

>
> On 2005 Jan 10, at 18:59, Phillip J. Eby wrote:
>
>> At 12:43 PM 1/10/05 -0500, Phillip J. Eby wrote:
>>> As a practical matter, all of the existing interface systems (Zope, 
>>> PyProtocols, and even the defunct Twisted implementation) treat 
>>> interface inheritance as guaranteeing substitutability for the base 
>>> interface, and do so transitively.
>>
>> An additional data point, by the way: the Eclipse Java IDE has an 
>> adaptation system that works very much like PEP 246 does, and it 
>> appears that in a future release they intend to support automatic 
>> adapter transitivity, so as to avoid requiring each provider of an 
>> interface to "provide O(n^2) adapters when writing the nth version of 
>> an interface."  IOW, their current release is transitive only for 
>> interface inheritance ala Zope or Twisted; their future release will 
>> be transitive for adapter chains ala PyProtocols.
>
> This is definitely relevant prior art, so thanks for pointing it out.  
> If interfaces change so often that 'n' can become worryingly high, 
> this is a valid concern.  In my world, though, published interfaces do 
> NOT change as often as to require such remedies;-).

...that was a bit too flippant -- I apologize.  It DOES happen that 
interfaces keep changing, and other situations where "adapter-chain 
transitivity" is quite handy do, absolutely!, occur, too.  Reflecting 
on Microsoft's QI (QueryInterface), based on a very strong injunction 
against changing interfaces and yet mandating transitivity, points that 
out -- that's prior art, too, and a LOT more of it than Eclipse can 
accumulate any time soon, considering how long COM has been at the 
heart of Microsoft's components strategy, how many millions of 
programmers have used or abused it.  Still, QI's set of constraints, 
amounting to a full-fledged equivalence relationship among all the 
"adapters" for a single underlying "object", is, I fear, stronger than 
we can impose (so it may be that Eclipse is a better parallel, but I 
know little of it while COM is in my bones, so that's what I keep 
thinking of;-).

So, I see transitivity as a nice thing to have _IF_ it's something that 
gets explicitly asserted for a certain adapter -- if the adapter has to 
explicitly state to the system that it "isn't lossy" (maybe), or "isn't 
noisy" (perhaps more useful), or something like that... some amount of 
reassurance about the adapter that makes it fully safe to use in such a 
chain.

Maybe it might suffice to let an adapter which IS 'lossy' (or, more 
likely, one that is 'noisy') state the fact.  I'm always reluctant by 
instinct to default to convenient but risky behavior, trusting 
programmers to explicitly assert otherwise when needed; but in many 
ways this kind of design is a part of Python and works fine (_with_ the 
BDFL's fine nose/instinct for making the right compromise between 
convenience and safety in each case, of course).

I'm still pondering the "don't adapt an adapter" suggestion, which 
seems a sound one, and yet also seems to be, intrinsically, what 
transitivity-by-chaining does.  Note that QI does not suffer from this, 
because it lets you get the underlying object identity (IUnknown) from 
any interface adapter.  Maybe, just maybe, we should also consider that 
-- a distinguished protocol bereft of any real substance but acting as 
a flag for "real unadapted object identity".  Perhaps we could use 
'object' for that, at least if the flow of logic in 'adapt' stays as in 
the current PEP 246 draft (i.e., __conform__ is given a chance before 
isinstance triggers -- so, all adapters could __conform__ to object by 
returning the underlying object being adapted, while other objects 
without such a feature in __conform__ would end up with 'adapt(x, 
object) is x').  Or, if object in this role turns out to be confusing, 
IDentity (;-) or some other specially designed protocol.

If we had this ability to "get at the underlying object" we could at 
least write clearer axioms about what transitivity must mean, as well 
as, help out with the "adapting an adapter" problems.  E.g., imagine:

def f(x: IFoo, y: IFoo):
     if x is y: ...

that wouldn't work if adapt(x, IFoo) returns a separate adapter each 
time, which is the most likely situation (think, again, of str->file 
adaptation by StringIO wrapping); but recovering underlying identities 
by "adapt(x, object) is adapt(y, object)" would work.


I don't think that IUnknown or an equivalent, per se, can do *instead* 
of the need to have an adapter explicitly state it's non-noisy (or VV). 
  Besides the need to check for object identity, which is pretty rare 
except when writing axioms, invariants or pre/post-conds;-), the 
IUnknown equivalent would perhaps be more of a conceptual/philosophical 
'prop' than a practically useful feature -- while I see the ability to 
block unintended consequences of inheritance and transitivity (or even 
better, state explicitly when those consequences are wanted, even if 
that should be 90% of the time...) as practically very, VERY useful, 
even if "conceptually" or "philosophically" dubious.



Alex



More information about the Python-Dev mailing list