Re: [Python-Dev] PEP 246, redux

2005-01-14 Thread Carlos Ribeiro
On Fri, 14 Jan 2005 08:50:27 +0100, Alex Martelli [EMAIL PROTECTED] wrote:
 Ooops -- sorry; I wouldn't have imagined Brazilian hits would swamp the
 google hits to that extent, mostly qualifying post-grad courses and the
 like... seems to be an idiom there for that.

'Lato sensu' is used to indicate short post-graduate level courses
that don't give one any recognized degree such as 'MSc', or 'master'.
It's pretty much like a specialization course on some specific area,
usually offered by small private universities. It's like a fever
around here - everyone does just to add something to the resume - and
has spawned a entire branch in the educational industry (and yeah,
'industry' is the best word for it).

Some schools refer to traditional post graduate courses as 'stricto
sensu'. I don't have the slightest idea about where they did get this
naming from. It's also amazing how many hits you'll get for the wrong
spelling: 'latu sensu'  'strictu sensu', mostly from Brazil, and also
from some spanish-speaking countries.

 Also, a reflection: taxonomy, the classification of things (living
 beings, rocks, legal precedents, ...) into categories, is a discipline
 with many, many centuries of experience behind it.  I think it is
 telling that taxonomists found out they require _two_ kinds of
 ``inheritance'' to do their job (no doubt there are all kind of
 _nuances_, but specialized technical wording exists for two kinds:
 strict-sense and broad-sense)... they need to be able to assert
 that A is a B _broadly speaking_ (or specifically _strictly
 speaking_) so often that they evolved specific terminology.  Let's
 hope it doesn't take OOP many centuries to accept that both stricto
 sensu inheritance (Liskovianly-correct) AND lato sensu inheritance
 are needed to do _our_ jobs!-)

Good point!

-- 
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: [EMAIL PROTECTED]
mail: [EMAIL PROTECTED]
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-13 Thread Alex Martelli
On 2005 Jan 12, at 21:42, Phillip J. Eby wrote:
   ...
Anyway, hopefully this post and the other one will be convincing that 
considering ambiguity to be an error *reinforces* the idea of I-to-I 
perfection, rather than undermining it.  (After all, if you've written 
a perfect one, and there's already one there, then either one of you 
is mistaken, or you are wasting your time writing one!)
I'd just like to point out, as apparently conceded in your fair 
enough sentence in another mail, that all of this talk of wasting 
your time writing is completely unfounded.  Since that fair enough 
of yours was deeply buried somewhere inside this huge conversation, 
some readers might miss the fact that your numerous repetitions of the 
similar concept in different words are just invalid, because, to recap:

Given four interfaces A, B, C, D, there may be need of each of the 
single steps A-B, A-C, B-D, C-D.  Writing each of these four 
adapters can IN NO WAY be considered wasting your time writing one, 
because there is no way a set of just three out of the four can be used 
to produce the fourth one.

The only redundancy comes strictly because of transitivity being 
imposed automatically: at the moment the fourth one of these four 
needed adapters gets registered, there appear to be two same-length 
minimal paths A-x-D (x in {B, C}).  But inferring _from this 
consequence of transitivity_ that there's ANYTHING wrong with any of 
the four needed adapters is a big unwarranted logical jump -- IF one 
really trusted all interface-interface adapters to be perfect, as is 
needed to justify transitivity and as you here claims gets reinforced 
(?!).

Thinking of it as redundancy is further shown to be fallacious 
because the only solution, if each of those 4 adapters is necessary, is 
to write and register a FIFTH one, A-D directly, even if one has no 
interest whatsoever in A-D adaptation, just to shut up the error or 
warning (as you say, there may be some vague analogy to static typing 
here, albeit in a marginal corner of the stage rather than smack in the 
spotlight;-).

Yes, there is (lato sensu) non-determinism involved, just like in, 
say:
for k in d:
print k
for a Python dictionary d - depending on how d was constructed and 
modified during its lifetime (which may in turn depend on what order 
modules were imported, etc), this produces different outputs.  Such 
non-determinism may occasionally give some problems to unwary 
programmers (who could e.g. expect d1==d2 -- repr(d1)==repr(d2) when 
keys and values have unique repr's: the right-pointing half of this 
implication doesn't hold, so using repr(d) to stand in for d when you 
need, e.g., a set of dictionaries, is not quite sufficient); such 
problems at the margin appear to be generally considered acceptable, 
though.

I seems to me that you do at least feel some unease at the whole 
arrangement, given that you say this whole debate has made me even 
less enamored of adaptation, as it's not clear to me that any _other_ 
aspect of this whole debate was quite as problematic (e.g. issues 
such as how to best get a special method from class rather than 
instance -- while needing to be resolved for adaptation just as much 
as for copy.py etc -- hardly seem likely to have been the ones 
prompting you to go looking for a cleaner, more intuitive way to do 
it outside of the canonical, widespread approach to OOP).

Anyway -- I'm pointing out that what to put in a rewrite of PEP 246 as 
a result of all this is anything but obvious at this point, at least to 
me.

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-13 Thread Phillip J. Eby
At 10:35 AM 1/13/05 +, Paul Moore wrote:
Now, a lot of the talk has referred to implicit adaptation. I'm
still struggling to understand how that concept applies in practice,
beyond the case of adaptation chains - at some level, all adaptation
is explicit, insofar as it is triggered by an adapt() call.
It's implicit in that the caller of the code that contains the adapt() 
call carries no visible indication that adaptation will take place.


   It's *still* not intuitively incorrect to me, but there's a couple
 things I can think of...

 (a) After you adapted the path to the file, and have a side-effect of
 opening a file, it's unclear who is responsible for closing it.
 (b) The file object clearly has state the path object doesn't have, like
 a file position.
 (c) You can't  go adapting the path object to a file whenever you
 wanted, because of those side effects.
In the context of my example above, I was assuming that C was an
interface (whatever that might be). Here, you're talking about
adapting to a file (a concrete class), which I find to be a much
muddier concept.
This is very much a best practices type of issue, though. I don't
see PEP 246 mandating that you *cannot* adapt to concrete classes, but
I can see that it's a dangerous thing to do.
Even the string-path adaptation could be considered suspect. Rather,
you should be defining an IPath *interface*, with operations such as
join, basename, and maybe open. Then, the path class would have a
trivial adaptation to IPath, and adapting a string to an IPath would
likely do so by constructing a path object from the string. From a
practical point of view, the IPath interface adds nothing over
adapting direct to the path class, but for the purposes of clarity,
documentation, separation of concepts, etc, I can see the value.
This confusion was another reason for the Duck-Typing Adaptation 
proposal; it's perfectly fine to take a 'path' class and duck-type an 
interface from it: i.e when you adapt to 'path', then if you call 
'basename' on the object, you will either:

1. Invoke a method that someone has claimed is semantically equivalent to 
path.basename, OR

2. Get a TypeError indicating that the object you're using doesn't have 
such an operation available.

In effect, this is the duck-typing version of a Java cast: it's more 
dynamic because it doesn't require you to implement all operations up 
front, and also because third parties can implement the operations and add 
them, and because you can define abstract operations that can implement 
operations in terms of other operations.


Some mistakes are easier to avoid if you have the correct conceptual
framework. I suspect that interfaces are the conceptual framework
which make adaptation fall into place. If so, then PEP 246, and
adaptation per se, is always going to be hard to reason about for
people without a background in interfaces.
Exactly, and that's a problem -- so, I think I've invented (or reinvented, 
one never knows) the concept of a duck interface, that requires no 
special background to understand or use, because (for example) it has no 
inheritance except normal inheritance, and involves no adapter classes 
anywhere.  Therefore, the reasoning you already apply to ordinary Python 
classes just works.  (Versus e.g. the interface-logic of Zope and 
PyProtocols, which is *not* ordinary Python inheritance.)


Hmm. I think I just disqualified myself from making any meaningful 
comments :-)
And I just requalified you.  Feel free to continue commenting.  :)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-13 Thread Phillip J. Eby
At 09:34 AM 1/13/05 -0500, Clark C. Evans wrote:
On Thu, Jan 13, 2005 at 10:35:39AM +, Paul Moore wrote:
| One thing I feel is key is the fact that adaptation is a *tool*, and
| as such will be used in different ways by different people. That is
| not a bad thing, even if it does mean that some people will abuse the tool.
|
| Now, a lot of the talk has referred to implicit adaptation. I'm
| still struggling to understand how that concept applies in practice,
| beyond the case of adaptation chains - at some level, all adaptation
| is explicit, insofar as it is triggered by an adapt() call.
The 'implicit' adaptation refers to the automagical construction of
composite adapters assuming that a 'transitive' property holds.
Maybe some folks are using the term that way; I use it to mean that in this 
code:

   someOb.something(aFoo)
'aFoo' may be implicitly adapted because the 'something' method has a 
type declaration on the parameter.

Further, 'something' might call another method with another type 
declaration, passing the adapted version of 'foo', which results in you 
possibly getting implicit transitive adaptation *anyway*, without having 
intended it.

Also, if adapters have per-adapter state, and 'someOb.something()' is 
expecting 'aFoo' to keep some state it puts there across calls to methods 
of 'someOb', then this code won't work correctly.

All of these things are implicit adaptation issues, IMO, and exist even 
withoutPyProtocols-style transitivity.  Duck adaptation solves these 
issues by prohibiting per-adapter state and by making adaptation 
order-insensitive.  (I.e. adapt(adapt(a,B),C) should always produce the 
same result as adapt(a,C).)

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-13 Thread Clark C. Evans
On Thu, Jan 13, 2005 at 08:40:56PM +0100, Alex Martelli wrote:
| The other issue with registries (and why I avoided them in the 
| origional) is that they often require a scoping; in this case, 
| the path taken by one module might be different from the one 
| needed by another.
| 
| I think that should not be supported, just like different modules 
| cannot register different ways to copy.copy(X) for the same X.  One 
| size had better fit all, be it a single specific adapter or potentially 
| a path thereof.

Sounds good.

| Ok.  I just think you all are solving a problem that doesn't exist,
| 
| Apparently, the existence of the problem is testified by the experience 
| of the Eclipse developers (who are, specifically, adapting plugins: 
| Eclipse being among the chief examples f plugin-based architecture... 
| definitely an N-players scenario).

Some specific examples from Eclipse developers would help then,
especially ones that argue strongly for automagical transitive
adaptation.  That is, ones where an alternative approach that
is not automatic is clearly inferior.

|A component developer X and a framework developer Y both
|have stuff that an application developer A is putting
|together.  The goal is for A to not worry about _how_ the
|components and the framework fit; to automatically find
|the glue code.
... 
| I'm quite ready to consider the risk of having too-thick combined 
| layers of glue resulting from adaptation (particularly but not 
| exclusively with transitivity): indeed PJE's new ideas may be seen as a 
| novel way to restart-from-scratch and minimize glue thickness in the 
| overall resulting concoction.

I do like PJE's idea, since it seems to focus on declaring individual 
functions rather than on sets of functions; but I'm still unclear
what problem it is trying to solve.

| But the optional ability for 
| particularly skilled glue-layers to have that extra layer which makes 
| everything better should perhaps not be discounted.  Although, 
| considering PJE's new just-started effort, it may well be wisest for 
| PEP 246 to stick to a minimalist attitude -- leave open the possibility 
| of future additions or alterations but only specify that minimal core 
| of functionality which we all _know_ is needed.

I'd rather not be pushing for a powerful regsistry mechansim unless
we have solid evidence that the value it provides outweighs the costs
that it incurres.

| I strongly disagree; the most useful adapters are the ones that
| discard unneeded information.
| 
| The Facade design pattern?  It's useful, but I disagree that it's most 
| useful when compared to general Adapter

My qualification was not very well placed.  That said, I don't see any 
reason why a facade can't also be asked for via the adapt() mechanism.

| So please explain what's imperfect in wrapping a str into a StringIO?

It adds information, and it implies mutability which the underlying
object is not.  In short, it's quite a different animal from a String,
which is why String-StringIO is a great example for an adapter.

| | What about registered explicitly as being suitable for transitivity,
| | would that suffice?
| 
| I suppose so.  But I think it is a bad idea for a few reasons:
| 
|   1. it seems to add complexity without a real-world justifcation,
|  let's go without it; and add it in a later version if it turns
|  out to be as valueable as people think
| 
| Particularly in the light of PJE's newest ideas, being spare and 
| minimal in PEP 246 does sound good, as long as we're not shutting and 
| bolting doors against future improvements.

Agreed!

|   2. different adapters have different intents...
|
| If you've ever looked into quality of data issues in huge databases, 
| you know that these are two (out of thousands) typical problems -- but 
| not problems in _adaptation_, in fact.

I deal with these issues all of the time; but what I'm trying to
express with the example is that someone may _think_ that they are
writing a perfect adapter; but they may be wrong, on a number of
levels.  It's not so much to say what is good, but rather to 
challenge the notion of a 'perfect adapter'. 

| In short, unless a human is giving the 'ok' to an adapter's
| use, be it the application, framework, or component developer,
| then I'd expect wacko bugs.
| 
| A lot of the data quality problems in huge databases come exactly from 
| humans -- data entry issues, form design issues, ... all the way to 
| schema-design issues.  I don't see why, discussing a data-quality 
| problem, you'd think that having a human OK whatsoever would help wrt 
| having a formalized rule (e.g. a database constraint) do it.

The point I was trying to make is that automatically constructing
adapters isn't a great idea unless you have someone who can vouche
for the usefulness.  In other words, I picture this as a physics
story problem, where a bunch of numbers are given with units. While
the units may keep you in check, 

Re: [Python-Dev] PEP 246, redux

2005-01-13 Thread Paul Moore
On Thu, 13 Jan 2005 13:43:53 -0800, Paramjit Oberoi [EMAIL PROTECTED] wrote:
 On Thu, 13 Jan 2005 20:40:56 +0100, Alex Martelli [EMAIL PROTECTED] wrote:
 
  So please explain what's imperfect in wrapping a str into a StringIO?
 
 If I understand Philip's argument correctly, the problem is this:
 
 def print_next_line(f: file):
 print f.readline()
 
 s = line 1\n line 2
 
 print_next_line(s)
 print_next_line(s)
 
 This will print line 1 twice.

Nice example!

The real subtlety here is that

f = adapt(s, StringIO)
print_next_line(f)
print_next_line(f)

*does* work - the implication is that for the original example to
work, adapt(s, StringIO) needs to not only return *a* wrapper, but to
return *the same wrapper* every time. Which may well break *other*
uses, which expect a new wrapper each time.

But the other thing that this tends to make me believe even more
strongly is that using Guido's type notation for adaptation is a bad
thing.

def print_next_line(f):
ff = adapt(f, file)
print ff.readline()

Here, the explicit adaptation step in the definition of the function
feels to me a little more obviously a wrapping operation which may
reinitialise the adapter - and would raise warning bells in my mind if
I thought of it in terms of a string-StringIO adapter.

Add this to the inability to recover the original object (for
readaptation, or passing on as an argument to another function), and
I'm very concerned about Guido's type notation being used as an
abbreviation for adaptation...

Paul.
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-13 Thread James Y Knight
On Jan 13, 2005, at 12:46 PM, Clark C. Evans wrote:
My current suggestion to make 'transitive adaption' easy for a
application builder (one putting togeher components) has a few
small parts:
  - If an adaptation is not found, raise an error, but list in
the error message two additional things: (a) what possible
adaptation paths exist, and (b) how to register one of
these paths in their module.
  - A simple method to register an adaption path, the error message
above can even give the exact line needed,
   adapt.registerPath(from=A,to=C,via=B)
I'd just like to note that this won't solve my use case for transitive 
adaptation. To keep backwards compatibility, I can't depend on the 
application developer to register an adapter path from A through 
IResource to INewResource. Trying to adapt A to INewResource needs to 
just work. I can't register the path either, because I (the framework 
author) don't know anything about A.

A solution that would work is if I have to explicitly declare the 
adapter from IResource to INewResource as 'safe', as long as I don't 
also have to declare the adapter from A to IResource as 'safe'. (That 
is, I suppose -- in a transitive adapter chain, all except one adapter 
in the chain would have to be declared 'safe').

I don't know whether or not it's worthwhile to have this encoded in the 
framework, as it is clearly possible to do it on my own in any case. 
I'll leave that for others to debate. :)

James
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-13 Thread Alex Martelli
On 2005 Jan 14, at 04:08, David Ascher wrote:
Alex Martelli wrote:
Yes, there is (lato sensu) non-determinism involved, just like in, 
say:
for k in d:
print k
Wow, it took more than the average amount of googling to figure out 
that lato sensu means broadly speaking,
Ooops -- sorry; I wouldn't have imagined Brazilian hits would swamp the 
google hits to that extent, mostly qualifying post-grad courses and the 
like... seems to be an idiom there for that.

 and occurs as sensu lato with a 1:2 ratio.
In Latin as she was spoken word order is very free, but the issue here 
is that _in taxonomy specifically_ (which was the way I intended the 
form!) the sensu lato order vastly predominates.  Very exhaustive 
discussion of this word order choice in taxonomy at 
http://www.forum-one.org/new-1967018-4338.html, btw (mostly about 
sensu scricto, the antonym).

I learned something today! ;-)
Me too: about Brazilian idiom, and about preferred word-order use in 
Aquinas and Bonaventura.

Also, a reflection: taxonomy, the classification of things (living 
beings, rocks, legal precedents, ...) into categories, is a discipline 
with many, many centuries of experience behind it.  I think it is 
telling that taxonomists found out they require _two_ kinds of 
``inheritance'' to do their job (no doubt there are all kind of 
_nuances_, but specialized technical wording exists for two kinds: 
strict-sense and broad-sense)... they need to be able to assert 
that A is a B _broadly speaking_ (or specifically _strictly 
speaking_) so often that they evolved specific terminology.  Let's 
hope it doesn't take OOP many centuries to accept that both stricto 
sensu inheritance (Liskovianly-correct) AND lato sensu inheritance 
are needed to do _our_ jobs!-)

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Jim Fulton
Clark C. Evans wrote:
On Tue, Jan 11, 2005 at 12:54:36PM -0500, Phillip J. Eby wrote:
...
| * In my experience, incorrectly deriving an interface from another is the 
| most common source of unintended adaptation side-effects, not adapter 
| composition

It'd be nice if interfaces had a way to specify a test-suite that
could be run against a component which claims to be compliant.   For
example, it could provide invalid inputs and assert that the proper
errors are returned, etc.
We've tried this in Zope 3 with very limited success.  In fact,
so far, our attempts have provided more pain than their worth.
The problem is that interfaces are usually abstract enough that
it's very difficult to write generic tests.  For example,
many objects implement mapping protocols, but place restrictions
on the values stored.  It's hard to provide generic tests that don't
require lots of inconvenient hooks.  There are exceptions of course.
Our ZODB storage tests use a generic storage-interface test, but this
is possible because the ZODB storage interfaces are extremely
concrete.
Jim
--
Jim Fulton   mailto:[EMAIL PROTECTED]   Python Powered!
CTO  (540) 361-1714http://www.python.org
Zope Corporation http://www.zope.com   http://www.zope.org
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 14:44, Paul Moore wrote:
On Wed, 12 Jan 2005 00:33:22 +0100, Alex Martelli [EMAIL PROTECTED] 
wrote:
But adaptation is not transmission!  It's PERFECTLY acceptable for an
adapter to facade: to show LESS information in the adapted object than
was in the original.  It's PERFECTLY acceptable for an adapter to say
this piece information is not known when it's adapting an object for
which that information, indeed, is not known.  It's only CONJOINING 
the
two perfectly acceptable adapters, as transitivity by adapter chain
would do automatically, that you end up with a situation that is
pragmatically undesirable: asserting that some piece of information is
not known, when the information IS indeed available -- just not by the
route automatically taken by the transitivity-system.
[Risking putting my head above the parapet here :-)]
If you have adaptations A-B, B-C, and A-C, I would assume that the
system would automatically use the direct A-C route rather than
A-B-C. I understand that this is what PyProtocols does.
Yes, it is.
Are you mistakenly thinking that shortest-possible-route semantics
aren't used? Maybe the PEP should explicitly require such semantics.
No, I'm not.  I'm saying that if, by mistake, the programmer has NOT 
registered the A-C adapter (which would be easily coded and work 
perfectly), then thanks to transitivity, instead of a clear and simple 
error message leading to immediate diagnosis of the error, they'll get 
a subtle unnecessary degradation of information and resulting reduction 
in information quality.

PyProtocols' author claims this can't happen because if adapters A-B 
and B-C are registered then each adapter is always invariably claiming 
to be lossless and perfect.  However, inconsistently with that stance, 
I believe that PyProtocols does give an error message if it finds two 
adaptation paths of equal minimum length, A-B-C or A-Z-C -- if it 
is truly believed that each adaptation step is lossless and perfect, 
it's inconsistent to consider the existence of two equal-length paths 
an error... either path should be perfect, so just picking either one 
of them should be a perfectly correct strategy.

If I'm missing the point here, I apologise. But I get the feeling that
something's getting lost in the discussions.
The discussions on this subject always and invariably get extremely 
long (and often somewhat heated, too), so it's quite possible that a 
lot is getting lost along the way, particularly to any other reader 
besides the two duelists.  Thus, thanks for focusing on one point that 
might well be missed by other readers (though not by either PJE or 
me;-) and giving me a chance to clarify it!

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 02:27 PM 1/12/05 +, Mark Russell wrote:
I strongly prefer *not* to have A-B and B-C automatically used to
construct A-C.  Explicit is better than implicit, if in doubt don't
guess, etc etc.
So I'd support:
- As a first cut, no automatic transitive adaptation
- Later, and only if experience shows there's a need for it,
Well, by the experience of the people who use it, there is a need, so it's 
already later.  :)  And at least my experience *also* shows that 
transitive interface inheritance with adaptation is much easier to 
accidentally screw up than transitive adapter composition -- despite the 
fact that nobody objects to the former.

But if you'd like to compare the two approaches pragmatically, try using 
both zope.interface and PyProtocols, and see what sort of issues you run 
into.  They have pretty much identical interface syntax, and you can use 
the PyProtocols declaration API and 'adapt' function to do interface 
declarations for either Zope interfaces or PyProtocols interfaces -- and 
the adaptation semantics follow Zope if you're using Zope interfaces.  So, 
you can literally flip between the two by changing where you import the 
'Interface' class from.

Both Zope and PyProtocols support the previous draft of PEP 246; the new 
draft adds only two new features:

* Ability for a class to opt out of the 'isinstance()' check for a base 
class (i.e., for a class to say it's not substitutable for its base class, 
for Alex's private inheritance use case)

* Ability to have a global type-protocol adapter registry
Anyway, I'm honestly curious as to whether anybody can find a real 
situation where transitive adapter composition is an *actual* problem, as 
opposed to a theoretical one.  I've heard a lot of people talk about what a 
bad idea it is, but I haven't heard any of them say they actually tried 
it.  Conversely, I've also heard from people who *have* tried it, and liked 
it.  However, at this point I have no way to know if this dichotomy is just 
a reflection of the fact that people who don't like the idea don't try it, 
and the people who either like the idea or don't care are open to trying it.

The other thing that really blows my mind is that the people who object to 
the idea don't get that transitive interface inheritance can produce the 
exact same problem, and it's more likely to happen in actual *practice*, 
than it is in theory.

As for the issue of what should and shouldn't exist in Python, it doesn't 
really matter; PEP 246 doesn't (and can't!) *prohibit* transitive 
adaptation.  However, I do strongly object to the spreading of theoretical 
FUD about a practical, useful technique, much as I would object to people 
saying that using significant whitespace is braindead who had never tried 
actually using Python.  The theoretical problems with transitive adapter 
composition are in my experience just as rare as whitespace-eating 
nanoviruses from outer space.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Guido van Rossum
[Alex]
 I'm saying that if, by mistake, the programmer has NOT
 registered the A-C adapter (which would be easily coded and work
 perfectly), then thanks to transitivity, instead of a clear and simple
 error message leading to immediate diagnosis of the error, they'll get
 a subtle unnecessary degradation of information and resulting reduction
 in information quality.

I understand, but I would think that there are just as many examples
of cases where having to register a trivial A-C adapter is much more
of a pain than it's worth; especially if there are a number of A-B
pairs and a number of B-C pairs, the number of additional A-C pairs
needed could be bewildering.

But I would like to see some input from people with C++ experience.
C++ goes to great lengths to pick automatic conversions (which perhaps
aren't quite the same as adaptations but close enough for this
comparison to work) and combine them. *In practice*, is this a benefit
or a liability?

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 16:12, Phillip J. Eby wrote:
At 02:27 PM 1/12/05 +, Mark Russell wrote:
I strongly prefer *not* to have A-B and B-C automatically used to
construct A-C.  Explicit is better than implicit, if in doubt don't
guess, etc etc.
So I'd support:
- As a first cut, no automatic transitive adaptation
- Later, and only if experience shows there's a need for it,
Well, by the experience of the people who use it, there is a need, so 
it's already later.  :)  And at least my experience *also* shows 
that transitive interface inheritance with adaptation is much easier 
to accidentally screw up than transitive adapter composition -- 
despite the fact that nobody objects to the former.
A-hem -- I *grumble* about the former (and more generally the fact that 
inheritance is taken as so deucedly *committal*:-).  If it doesn't 
really count as a complaint it's only because I doubt I can do 
anything about it and I don't like tilting at windmills.  But, I _DO_ 
remember Microsoft's COM, with inheritance of interface *NOT* implying 
anything whatsoever (except the fact that the inheriting one has all 
the methods of the inherited one with the same signature, w/o having to 
copy and paste, plus of course you can add more) -- I remember that 
idea with fondness, as I do many other features of a components-system 
that, while definitely not without defects, was in many respects a 
definite improvement over the same respects in its successors.

The other thing that really blows my mind is that the people who 
object to the idea don't get that transitive interface inheritance can 
produce the exact same problem, and it's more likely to happen in 
actual *practice*, than it is in theory.
Believe me, I'm perfectly glad to believe that [a] implied transitivity 
in any form, and [b] hypercommittal inheritance, cause HUGE lots of 
problems; and to take your word that the combination is PARTICULARLY 
bug-prone in practice.  It's just that I doubt I can do anything much 
to help the world avoid that particular blight.

As for the issue of what should and shouldn't exist in Python, it 
doesn't really matter; PEP 246 doesn't (and can't!) *prohibit* 
transitive adaptation.  However, I do strongly object to the spreading 
of theoretical FUD about a practical, useful technique, much as I 
would object to people saying that using significant whitespace is 
braindead who had never tried actually using Python.  The theoretical 
problems with transitive adapter composition are in my experience just 
as rare as whitespace-eating nanoviruses from outer space.
Well, I'm not going to start real-life work on a big and complicated 
system (the kind where such problems would emerge) relying on a 
technique I'm already dubious about, if I have any say in the matter, 
so of course I'm unlikely to gain much real-life experience -- I'm 
quite content, unless somebody should be willing to pay me adequately 
for my work yet choose to ignore my advice in the matter;-), to rely on 
imperfect analogies with other experiences based on other kinds of 
unwanted and unwarranted but uncontrollable and unstoppable 
applications of transitivity by underlying systems and frameworks.

I already know -- you told us so -- that if I had transitivity as you 
wish it (uncontrollable, unstoppable, always-on) I could not any more 
write and register a perfectly reasonable adapter which fills in with a 
NULL an optional field in the adapted-to interface, without facing 
undetected degradation of information quality by that adapter being 
invisibly, uncontrollably chained up with another -- no error message, 
no nothing, no way to stop this -- just because a direct adapter wasn't 
correctly written and registered.  Just this detail, for me, is 
reason enough to avoid using any framework that imposes such 
noncontrollable transitivity, if I possibly can.

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


getattr and __mro__ (was Re: [Python-Dev] PEP 246, redux)

2005-01-12 Thread Thomas Heller
Armin Rigo [EMAIL PROTECTED] writes:

 ... is that the __adapt__() and __conform__() methods should work just
 like all other special methods for new-style classes.  The confusion
 comes from the fact that the reference implementation doesn't do that.
 It should be fixed by replacing:

conform = getattr(type(obj), '__conform__', None)

 with:

for basecls in type(obj).__mro__:
if '__conform__' in basecls.__dict__:
conform = basecls.__dict__['__conform__']
break
else:
# not found

 and the same for '__adapt__'.

 The point about tp_xxx slots is that when implemented in C with slots, you get
 the latter (correct) effect for free.  This is how metaconfusion is avoided in
 post-2.2 Python.  Using getattr() for that is essentially broken.  Trying to
 call the method and catching TypeErrors seems pretty fragile -- e.g. if you
 are calling a __conform__() which is implemented in C you won't get a Python
 frame in the traceback either.

I'm confused.  Do you mean that

   getattr(obj, somemethod)(...)

does something different than

   obj.somemethod(...)

with new style class instances?  Doesn't getattr search the __dict__'s
along the __mro__ list?

Thomas

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Guido van Rossum
[Alex]
 Of course, it's possible that some such wrappers are coded much
 more tighter c, so that in fact some roundabout A - X1 - X2 - C
 would actually be better performing than either A - B - C or A - Z
 - C, but using one of the shortest available paths appears to be a
 reasonable heuristic for what, if one assumes away any degradation,
 is after all a minor issue.

I would think that the main reason for preferring the shortest path is
the two degenerate cases, A-A (no adaptation necessary) and A-C (a
direct adapter is available). These are always preferable over longer
possibilities.

 Demanding that the set of paths of minimal available length has exactly
 one element is strange, though,

I think you're over-emphasizing this point (in several messages);
somehow you sound a bit like you're triumphant over having found a bug
in your opponent's reasoning.

[...]
 So, yes, I'd _also_ love to have two grades of inheritance, one of the
 total commitment kind (implying transitivity and whatever), and one
 more earthly a la ``I'm just doing some convenient reuse, leave me
 alone''.

I'll bet that the list of situations where occasionally you wish you
had more control over Python's behavior is a lot longer than that, and
I think that if we started implementing that wish list (or anybody's
wish list), we would soon find that we had destroyed Python's charming
simplicity.

My personal POV here: even when you break Liskov in subtle ways, there
are lots of situations where assuming substitutability has no ill
effects, so I'm happy to pretend that a subclass is always a subtype
of all of its base classes, (and their base classes, etc.). If it
isn't, you can always provide an explicit adapter to rectify things.

As an example where a subclass that isn't a subtype can be used
successfully, consider a base class that defines addition to instances
of the same class. Now consider a subclass that overrides addition to
only handle addition to instances of that same subclass; this is a
Liskov violation. Now suppose the base class also has a factory
function that produces new instances, and the subclass overrides this
to produce new instances of the subclass. Then a function designed to
take an instance of the base class and return the sum of the instances
produced by calling the factory method a few times will work perfectly
with a subclass instance as argument. Concrete:

class B:
def add(self, other: B) - B: ...
def factory(self) - B: ...

class C(B):
def add(self, other: C) - C: ... # other: C violates Liskov
def factory(self) - C: ...

def foo(x: B) - B:
x1 = x.factory()
x2 = x.factory()
return x1.add(x2)

This code works fine in today's python if one leaves the type
declarations out. I don't think anybody is served by forbidding it.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Guido van Rossum
[Phillip]
 As for the issue of what should and shouldn't exist in Python, it doesn't
 really matter; PEP 246 doesn't (and can't!) *prohibit* transitive
 adaptation.

Really? Then isn't it underspecified? I'd think that by the time we
actually implement PEP 246 in the Python core, this part of the
semantics should be specified (at least the default behavior, even if
there are hooks to change this).

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 16:26, Guido van Rossum wrote:
   ...
[Alex]
I'm saying that if, by mistake, the programmer has NOT
registered the A-C adapter (which would be easily coded and work
perfectly), then thanks to transitivity, instead of a clear and simple
error message leading to immediate diagnosis of the error, they'll get
a subtle unnecessary degradation of information and resulting 
reduction
in information quality.
I understand, but I would think that there are just as many examples
of cases where having to register a trivial A-C adapter is much more
of a pain than it's worth; especially if there are a number of A-B
pairs and a number of B-C pairs, the number of additional A-C pairs
needed could be bewildering.
Hm?  For any A and B there can be only one A-B adapter registered.  Do 
you mean a number of A-B1, B1-C1 ; A-B2, B2-C2; etc?  Because if it 
was B1-C and B2-C, as I understand the transitivity of PyProtocols, 
it would be considered an error.

But I would like to see some input from people with C++ experience.
Here I am, at your service.  I've done, taught, mentored, etc, much 
more C++ than Python in my life.  I was technical leader for the whole 
C - C++ migration of a SW house which at that time had more than 100 
programmers (just as I had earlier been for the Fortran - C migration 
back a few years previously, with around 30 programmers): I taught 
internal courses, seminars and workshops on C++, its differences from 
C, OO programming and design, Design Patterns, and later generic 
programming, the STL, and so on, and so forth.  I mentored a lot of 
people (particularly small groups of people that would later go and 
teach/mentor the others), pair-programmed in the most critical 
migrations across the breadth of that SW house's software base, etc, 
etc.  FWIW, having aced Brainbench's C++ tests (I was evaluating them 
to see if it would help us select among candidates claiming C++ 
skills), I was invited to serve for a while as one of their Most 
Valued Professionals (MVPs) for C++, and although I had concluded that 
for that SW house's purposes the tests weren't all that useful, I did, 
trying to see if I could help make them better (more suitable to test 
_real-world_ skills and less biased in favour of people with that 
language-lawyer or library-packrat kind of mentality I have, which 
is more useful in tests than out in the real world).

I hope I can qualify as a C++ expert by any definition.
C++ goes to great lengths to pick automatic conversions (which perhaps
aren't quite the same as adaptations but close enough for this
comparison to work)
I agree with you, though I believe PJE doesn't (he doesn't accept my 
experience with such conversions as a valid reason for me to be afraid 
of close enough for this comparison adaptations).

 and combine them. *In practice*, is this a benefit
or a liability?
It's in the running for the coveted Alex's worst nightmare prize, 
with a few other features of C++ - alternatively put, the prize for 
reason making Alex happiest to have switched to Python and _almost_ 
managed to forget C++ save when he wakes up screaming in the middle of 
the night;-).

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: getattr and __mro__ (was Re: [Python-Dev] PEP 246, redux)

2005-01-12 Thread Guido van Rossum
[Armin]
  ... is that the __adapt__() and __conform__() methods should work just
  like all other special methods for new-style classes.  The confusion
  comes from the fact that the reference implementation doesn't do that.
  It should be fixed by replacing:
 
 conform = getattr(type(obj), '__conform__', None)
 
  with:
 
 for basecls in type(obj).__mro__:
 if '__conform__' in basecls.__dict__:
 conform = basecls.__dict__['__conform__']
 break
 else:
 # not found
 
  and the same for '__adapt__'.
 
  The point about tp_xxx slots is that when implemented in C with slots, you 
  get
  the latter (correct) effect for free.  This is how metaconfusion is avoided 
  in
  post-2.2 Python.  Using getattr() for that is essentially broken.  Trying to
  call the method and catching TypeErrors seems pretty fragile -- e.g. if you
  are calling a __conform__() which is implemented in C you won't get a Python
  frame in the traceback either.

[Thomas]
 I'm confused.  Do you mean that
 
getattr(obj, somemethod)(...)
 
 does something different than
 
obj.somemethod(...)
 
 with new style class instances?  Doesn't getattr search the __dict__'s
 along the __mro__ list?

No, he's referring to the (perhaps not widely advertised) fact that

obj[X]

is not quite the same as

obj.__getitem__(X)

since the explicit method invocation will find
obj.__dict__[__getitem__] if it exists but the operator syntax will
start the search with obj.__class__.__dict__.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: getattr and __mro__ (was Re: [Python-Dev] PEP 246, redux)

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 16:44, Thomas Heller wrote:
   ...
   conform = getattr(type(obj), '__conform__', None)
   ...
I'm confused.  Do you mean that
   getattr(obj, somemethod)(...)
does something different than
   obj.somemethod(...)
with new style class instances?  Doesn't getattr search the __dict__'s
along the __mro__ list?
Yes, but getattr(obj, ... ALSO searches obj itself, which is what we're 
trying to avoid here.

getattr(type(obj), ... OTOH has a DIFFERENT problem -- it ALSO searches 
type(type(obj)), the metaclass, which we DON'T want.

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 17:40, Phillip J. Eby wrote:
At 04:36 PM 1/12/05 +0100, Alex Martelli wrote:
I already know -- you told us so -- that if I had transitivity as you 
wish it (uncontrollable, unstoppable, always-on) I could not any more 
write and register a perfectly reasonable adapter which fills in with 
a NULL an optional field in the adapted-to interface, without facing 
undetected degradation of information quality by that adapter being 
invisibly, uncontrollably chained up with another -- no error 
message, no nothing, no way to stop this -- just because a direct 
adapter wasn't correctly written and registered.
But why would you *want* to do this, instead of just explicitly 
converting?  That's what I don't understand.  If I were writing such a 
converter, I wouldn't want to register it for ANY implicit conversion, 
even if it was non-transitive!
Say I have an SQL DB with a table such as:
CREATE TABLE fullname (
first VARCHAR(50) NOT NULL,
middle VARCHAR(50),
last VARCHAR(50) NOT NULL,
-- snipped other information fields
)
Now, I need to record a lot of names of people, which I get from a vast 
variety of sources, so they come in as different types.  No problem: 
I'll just adapt each person-holding type to an interface which offers 
first, middle and last names (as well as other information fields, here 
snipped), using None to mean I don't know the middle name for a given 
person (that's what NULL means, after all: information unknown or the 
like; the fact that fullname.middle is allowed to be NULL indicates 
that, while it's of course BETTER to have that information, it's not a 
semantic violation if that information just can't be obtained nohow).

All of my types which hold info on people can at least supply first and 
last names; some but not all can supply middle names.  Fine, no 
problem: I can adapt them all with suitable adapters anyway, 
noninvasively, without having to typecheck, typeswitch, or any other 
horror.  Ah, the magic of adaptation!  So, I define an interface -- say 
with arbitrary syntax:

interface IFullname:
first: str
middle: str or None
last: str
# snipped other information fields
and my function to write a data record is just:
def writeFullname(person: IFullname):
# do the writing
So, I have another interface in a similar vein, perhaps to map to/from 
some LDAP and similar servers which provide a slightly different set of 
info fields:

interface IPerson:
firstName: str
lastName: str
userid: str
# snipped other stuff
I have some data about people coming in from LDAP and the like, which I 
want to record in that SQL DB -- the incoming data is held in types 
that implement IPerson, so I write an adapter IPerson - IFullname for 
the purpose.

If the datatypes are immutable, conversion is as good as adaptation 
here, as I mentioned ever since the first mail in which I sketched this 
case, many megabytes back.  But adaptation I can get automatically 
WITHOUT typechecking on what exactly is the concrete type I'm having to 
write (send to LDAP, whatver) this time -- a crucial advantage of 
adaptation, as you mention in the PyProtocols docs.  Besides, maybe in 
some cases some of those attributes are in fact properties that get 
computed at runtime, fetched from a slow link if and only if they're 
first required, whatever, or even, very simply, some datatype is 
mutable and I need to ensure I'm dealing with the current state of the 
object/record.  So, I'm not sure why you appear to argue for conversion 
against adaptation, or explicit typechecking against the avoidance 
thereof which is such a big part of adapt's role in life.

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 06:18 PM 1/12/05 +0100, Alex Martelli wrote:
On 2005 Jan 12, at 17:40, Phillip J. Eby wrote:
At 04:36 PM 1/12/05 +0100, Alex Martelli wrote:
I already know -- you told us so -- that if I had transitivity as you 
wish it (uncontrollable, unstoppable, always-on) I could not any more 
write and register a perfectly reasonable adapter which fills in with a 
NULL an optional field in the adapted-to interface, without facing 
undetected degradation of information quality by that adapter being 
invisibly, uncontrollably chained up with another -- no error message, 
no nothing, no way to stop this -- just because a direct adapter wasn't 
correctly written and registered.
But why would you *want* to do this, instead of just explicitly 
converting?  That's what I don't understand.  If I were writing such a 
converter, I wouldn't want to register it for ANY implicit conversion, 
even if it was non-transitive!
[snip lots of stuff]
I have some data about people coming in from LDAP and the like, which I 
want to record in that SQL DB -- the incoming data is held in types that 
implement IPerson, so I write an adapter IPerson - IFullname for the purpose.
This doesn't answer my question.  Obviously it makes sense to adapt in this 
fashion, but not IMPLICITLY and AUTOMATICALLY.  That's the distinction I'm 
trying to make.  I have no issue with writing an adapter like 
'PersonAsFullName' for this use case; I just don't think you should 
*register* it for automatic use any time you pass a Person to something 
that takes a FullName.


  So, I'm not sure why you appear to argue for conversion against 
adaptation, or explicit typechecking against the avoidance thereof which 
is such a big part of adapt's role in life.
Okay, I see where we are not communicating; where I've been saying 
conversion, you are taking this to mean, don't write an adapter, but 
what I mean is don't *register* the adapter for implicit adaptation; 
explicitly use it in the place where you need it.


___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 18:58, Phillip J. Eby wrote:
   ...
I have some data about people coming in from LDAP and the like, which 
I want to record in that SQL DB -- the incoming data is held in types 
that implement IPerson, so I write an adapter IPerson - IFullname 
for the purpose.
This doesn't answer my question.  Obviously it makes sense to adapt in 
this fashion, but not IMPLICITLY and AUTOMATICALLY.  That's the 
distinction I'm trying to make.  I have no issue with writing an 
adapter like 'PersonAsFullName' for this use case; I just don't think 
you should *register* it for automatic use any time you pass a Person 
to something that takes a FullName.
I'm adapting incoming data that can be of any of a huge variety of 
concrete types with different interfaces.  *** I DO NOT WANT TO 
TYPECHECK THE INCOMING DATA *** to know what adapter or converter to 
apply -- *** THAT'S THE WHOLE POINT *** of PEP 246.  I can't believe 
we're misunderstanding each other about this -- there MUST be 
miscommunication going on!


  So, I'm not sure why you appear to argue for conversion against 
adaptation, or explicit typechecking against the avoidance thereof 
which is such a big part of adapt's role in life.
Okay, I see where we are not communicating; where I've been saying 
conversion, you are taking this to mean, don't write an adapter, 
but what I mean is don't *register* the adapter for implicit 
adaptation; explicitly use it in the place where you need it.
Adaptation is not conversion is how I THOUGHT we had agreed to 
rephrase my unfortunate adaptation is not casting -- so if you're 
using conversion to mean adaptation, I'm nonplussed.

Needing to be explicit and therefore to typechecking/typeswitching to 
pick which adapter to apply is just what I don't *WANT* to do, what I 
don't want *ANYBODY* to have to do EVER, and the very reason I'm 
spending time and energy on PEP 246.  So, how would you propose I know 
which adapter I need, without spreading typechecks all over my 
bedraggled *CODE*?!?!

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Guido van Rossum
  [Alex]
  I'm saying that if, by mistake, the programmer has NOT
  registered the A-C adapter (which would be easily coded and work
  perfectly), then thanks to transitivity, instead of a clear and simple
  error message leading to immediate diagnosis of the error, they'll get
  a subtle unnecessary degradation of information and resulting
  reduction
  in information quality.

[Guido]
  I understand, but I would think that there are just as many examples
  of cases where having to register a trivial A-C adapter is much more
  of a pain than it's worth; especially if there are a number of A-B
  pairs and a number of B-C pairs, the number of additional A-C pairs
  needed could be bewildering.

[Alex]
 Hm?

I meant if there were multiple A's. For every Ai that has an Ai-B you
would also have to register a trivial Ai-C. And if there were
multiple C's (B-C1, B-C2, ...) then the number of extra adaptors to
register would be the number of A's *times* the number of C's, in
addition to the sum of those numbers for the atomic adaptors (Ai-B,
B-Cj).

  But I would like to see some input from people with C++ experience.
 
 Here I am, at your service.
[...]
 It's in the running for the coveted Alex's worst nightmare prize,

Aha. This explains why you feel so strongly about it.

But now, since I am still in favor of automatic combined adaptation
*as a last resort*, I ask you to consider that Python is not C++, and
that perhaps we can make the experience in Python better than it was
in C++. Perhaps allowing more control over when automatic adaptation
is acceptable?

For example, inteface B (or perhaps this should be a property of the
adapter for B-C?) might be marked so as to allow or disallow its
consideration when looking for multi-step adaptations. We could even
make the default don't consider, so only people who have to deal
with the multiple A's and/or multiple C's all adaptable via the same B
could save themselves some typing by turning it on.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 19:16, Guido van Rossum wrote:
   ...
[Alex]
Hm?
I meant if there were multiple A's. For every Ai that has an Ai-B you
would also have to register a trivial Ai-C. And if there were
multiple C's (B-C1, B-C2, ...) then the number of extra adaptors to
register would be the number of A's *times* the number of C's, in
addition to the sum of those numbers for the atomic adaptors (Ai-B,
B-Cj).
Ah, OK, I get it now, thanks.

But now, since I am still in favor of automatic combined adaptation
*as a last resort*, I ask you to consider that Python is not C++, and
that perhaps we can make the experience in Python better than it was
in C++. Perhaps allowing more control over when automatic adaptation
is acceptable?
Yes, that would be necessary to achieve parity with C++, which does now 
have the 'explicit' keyword (to state that a conversion must not be 
used as a step in a chain automatically constructed) -- defaults to 
acceptable in automatic chains for historical and backwards 
compatibility reasons.

For example, inteface B (or perhaps this should be a property of the
adapter for B-C?) might be marked so as to allow or disallow its
consideration when looking for multi-step adaptations. We could even
make the default don't consider, so only people who have to deal
with the multiple A's and/or multiple C's all adaptable via the same B
could save themselves some typing by turning it on.
Yes, this idea you propose seems to me to be a very reasonable 
compromise: one can get the convenience of automatic chains of 
adaptations but only when the adaptations involved are explicitly 
asserted to be OK for that.  I think that the property (of being OK for 
automatic/implicit/chained/transitive use) should definitely be one of 
the adaptation rather than of an interface, btw.

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 07:49 AM 1/12/05 -0800, Guido van Rossum wrote:
[Phillip]
 As for the issue of what should and shouldn't exist in Python, it doesn't
 really matter; PEP 246 doesn't (and can't!) *prohibit* transitive
 adaptation.
Really? Then isn't it underspecified?
No; I just meant that:
1. With its current hooks, implementing transitivity is trivial; 
PyProtocols' interface objects have an __adapt__ that does the transitive 
lookup.  So, as currently written, this is perfectly acceptable in PEP 246.

2. Given Python's overall flexibility, there's really no way to *stop* 
anybody from implementing it short of burying the whole thing in C and 
providing no way to access it from Python.  And then somebody can still 
implement an extension module.  ;)


 I'd think that by the time we
actually implement PEP 246 in the Python core, this part of the
semantics should be specified (at least the default behavior, even if
there are hooks to change this).
The default behavior *is* specified: it's just specified as whatever you 
want.  :)  What Alex and I are really arguing about is what should be the 
one obvious way to do it, and implicitly, what Python interfaces should do.

Really, the whole transitivity argument is moot for PEP 246 itself; PEP 246 
doesn't really care, because anybody can do whatever they want with 
it.  It's Python's standard interface implementation that cares; should 
its __adapt__ be transitive, and if so, how transitive?  (PEP 246's global 
registry could be transitive, I suppose, but it's only needed for 
adaptation to a concrete type, and I only ever adapt to interfaces, so I 
don't have any experience with what somebody might or might not want for 
that case.)

Really, the only open proposals remaining (i.e. not yet accepted/rejected 
by Alex) for actually *changing* PEP 246 that I know of at this point are:

1. my suggestion for how to handle the LiskovViolation use case by 
returning None instead of raising a special exception

2. that classic classes be supported, since the old version of PEP 246 
supported them and because it would make exceptions unadaptable otherwise.

The rest of our discussion at this point is just pre-arguing a 
not-yet-written PEP for how Python interfaces should handle adaptation.  :)

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 09:46 AM 1/12/05 -0800, Michael Chermside wrote:
This is a collection of responses to various things that don't appear
to have been resolved yet:
Phillip writes:
 if a target protocol has optional aspects, then lossy adaptation to it is
 okay by definition.  Conversely, if the aspect is *not* optional, then
 lossy adaptation to it is not acceptable.  I don't think there can really
 be a middle ground; you have to decide whether the information is required
 or not.
I disagree. To belabor Alex's example, suppose LotsOfInfo has first, middle,
and last names; PersonName has first and last, and FullName has first,
middle initial and last. FullName's __doc__ specifically states that if
the middle name is not available or the individual does not have a middle
name, then None is acceptable.
The error, IMO, is in registering an interface-to-interface adapter from 
PersonName to FullName; at best, it should be explicitly registered only 
for concrete classes that lack some way to provide a middle name.

If you don't want to lose data implicitly, don't register an implicit 
adaptation that loses data.


You're probably going to say okay, then register a LotsOfInfo-FullName
converter, and I agree. But if no such converter is registered, I
would rather have a TypeError then an automatic conversion which produces
incorrect results.
Then don't register a data-losing adapter for implicit adaptation for any 
possible input source; only the specific input sources that you need it for.


 it's difficult because intuitively an interface defines a *requirement*, so
 it seems logical to inherit from an interface in order to add requirements!
Yes... I would fall into this trap as well until I'd been burned a few times.
It's burned me more than just a few times, and I *still* sometimes make it 
if I'm not paying attention.  It's just too easy to make the mistake.  So, 
I'm actually open to considering dropping interface inheritance.

For adapters, I think it's much harder to make this mistake because you 
have more time to think about whether your adapter is universal or not, and 
you can always err on the safe side.  In truth, I believe I much more 
frequently implement class-to-interface adapters than 
interface-to-interface ones.  I can always go back later and declare the 
adapter as interface-to-interface if I want, so there's no harm in starting 
them out as class-to-interface adapters.


Gee... I'm understanding the problem a little better, but elegant
solutions are still escaping me.
My solution is to use class-to-interface adaptation for most adaptation, 
and interface-to-interface adaptation only when the adaptation can be 
considered correct by definition.  It seems to work for me.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Clark C. Evans
On Wed, Jan 12, 2005 at 10:16:14AM -0800, Guido van Rossum wrote:
| But now, since I am still in favor of automatic combined adaptation
| *as a last resort*, I ask you to consider that Python is not C++, and
| that perhaps we can make the experience in Python better than it was
| in C++. Perhaps allowing more control over when automatic adaptation
| is acceptable?
| 
| For example, inteface B (or perhaps this should be a property of the
| adapter for B-C?) might be marked so as to allow or disallow its
| consideration when looking for multi-step adaptations. We could even
| make the default don't consider, so only people who have to deal
| with the multiple A's and/or multiple C's all adaptable via the same B
| could save themselves some typing by turning it on.

How about not allowing transitive adaptation, by default, and
then providing two techniques to help the user cope:

  - raise a AdaptIsTransitive(AdaptationError) exception when
an adaptation has failed, but there exists a A-C pathway
using an intermediate B 

  - add a flag to adapt, allowTransitive, which defaults to False

This way new developers don't accidently shoot their foot off, as
Alex warns; however, the price for doing this sort of thing is cheap.
The AdaptIsTransitive error could even explain the problem with a
dynamic error message like:

  You've tried to adapt a LDAPName to a FirstName, but no
   direct translation exists.  There is an indirect translation
   using FullName:  LDAPName - FullName - FirstName.  If you'd
   like to use this intermediate object, simply call adapt()
   with allowTransitive = True

Clark
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 05:02 PM 1/12/05 +0100, Alex Martelli wrote:
So, I think PEP 246 should specify that the step now called (e) [checking 
the registry] comes FIRST; then, an isinstance step [currently split 
between (a) and (d)], then __conform__ and __adapt__ steps [currently 
called (b) and (c)].
One question, and one suggestion.
The question: should the registry support explicitly declaring that a 
particular adaptation should *not* be used, thus pre-empting later phases 
entirely?  This would allow for the possibility of speeding lookups by 
caching, as well as the option to opt out of specific adaptations, which 
some folks seem to want.  ;)

The suggestion: rather than checking isinstance() in adapt(), define 
object.__conform__ such that it does the isinstance() check.  Then, Liskov 
violation is simply a matter of returning 'None' from __conform__ instead 
of raising a special error.


  Checking the registry is after all very fast: make the 2-tuple 
(type(obj), protocol), use it to index into the registry -- period.  So, 
it's probably not worth complicating the semantics at all just to fast 
path the common case.
Okay, one more suggestion/idea:
$ timeit -s d={}; d[1,2]=None d[1,2]
100 loops, best of 3: 1.65 usec per loop
$ timeit -s d={}; d[1]={2:None} d[1][2]
100 loops, best of 3: 0.798 usec per loop
This seems to suggest that using nested dictionaries could be faster under 
some circumstances than creating the two-tuple to do the lookup.  Of 
course, these are trivially-sized dictionaries and this is also measuring 
Python bytecode speed, not what would happen in C.  But it suggests that 
more investigation might be in order.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 20:39, Phillip J. Eby wrote:
   ...
 it's difficult because intuitively an interface defines a 
*requirement*, so
 it seems logical to inherit from an interface in order to add 
requirements!

Yes... I would fall into this trap as well until I'd been burned a 
few times.
It's burned me more than just a few times, and I *still* sometimes 
make it if I'm not paying attention.  It's just too easy to make the 
mistake.  So, I'm actually open to considering dropping interface 
inheritance.
What about accepting Microsoft's QueryInterface precedent for this?  I 
know that MS is a dirty word to many, but I did like much of what 
they did in COM, personally.  The QI precedent would be: you can 
inherit interface from interface, but that does NOT intrinsically imply 
substitutability -- it just means the inheriting interface has all the 
methods of the one being subclassed, with the same signatures, without 
having to do a nasty copy-and-paste.  Of course, one presumably could 
use NO_ADAPTER_NEEDED to easily (but explicitly: that makes a 
difference!) implement the common case in which the inheriting 
interface DOES want to assert that it's perfectly / losslessly / etc 
substitutable for the one being inherited.

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 09:05 PM 1/12/05 +0100, Alex Martelli wrote:
On 2005 Jan 12, at 20:39, Phillip J. Eby wrote:
It's burned me more than just a few times, and I *still* sometimes make 
it if I'm not paying attention.  It's just too easy to make the 
mistake.  So, I'm actually open to considering dropping interface inheritance.
What about accepting Microsoft's QueryInterface precedent for this?  I 
know that MS is a dirty word to many, but I did like much of what they 
did in COM, personally.  The QI precedent would be: you can inherit 
interface from interface, but that does NOT intrinsically imply 
substitutability -- it just means the inheriting interface has all the 
methods of the one being subclassed, with the same signatures, without 
having to do a nasty copy-and-paste.  Of course, one presumably could use 
NO_ADAPTER_NEEDED to easily (but explicitly: that makes a difference!) 
implement the common case in which the inheriting interface DOES want to 
assert that it's perfectly / losslessly / etc substitutable for the one 
being inherited.
Well, you and I may agree to this, but we can't agree on behalf of 
everybody else who hasn't been bitten by this problem, I'm afraid.

I checked PEAK and about 62 out of 150 interfaces inherited from anything 
else; it would not be a big deal to explicitly do the NO_ADAPTER_NEEDED 
thing, especially since PyProtocols has an 'advise' keyword that does the 
declaration, anyway; inheritance is just a shortcut for that declaration 
when you are using only one kind of interface, so the explicit way of 
defining NO_ADAPTER_NEEDED between two interfaces has only gotten used when 
mixing Zope or Twisted interfaces w/PyProtocols.

Anyway, I'm at least +0 on dropping this; the reservation is just because I 
don't think everybody else will agree with this, and don't want to be 
appearing to imply that consensus between you and me implies any sort of 
community consensus on this point.  That is, the adaptation from Alex and 
Phillip agree to community agrees is noisy at best!  ;)

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Carlos Ribeiro
On Wed, 12 Jan 2005 10:16:14 -0800, Guido van Rossum
[EMAIL PROTECTED] wrote:
 But now, since I am still in favor of automatic combined adaptation
 *as a last resort*, I ask you to consider that Python is not C++, and
 that perhaps we can make the experience in Python better than it was
 in C++. Perhaps allowing more control over when automatic adaptation
 is acceptable?
 
 For example, inteface B (or perhaps this should be a property of the
 adapter for B-C?) might be marked so as to allow or disallow its
 consideration when looking for multi-step adaptations. We could even
 make the default don't consider, so only people who have to deal
 with the multiple A's and/or multiple C's all adaptable via the same B
 could save themselves some typing by turning it on.

+1. BTW, I _do_ use adaptation, including the 'lossy' one described in
this scenario (where the mapping is imperfect, or incomplete). So
having some way to tell the adaptation framework that a particular
adapter is not suited to use in a transitive chain is a good thing
IMHO. Generically speaking, anything that puts some control on the
hands of the programmer - as long it does not stand in the way between
him and the problem - is good.

-- 
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: [EMAIL PROTECTED]
mail: [EMAIL PROTECTED]
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 20:51, Phillip J. Eby wrote:
   ...
There's a very simple reason.  If one is using only non-noisy 
adapters, there is absolutely no reason to ever define more than one 
adapter between the *same* two points.  If you do,
...but there's no harm whatsoever done, either.  If I have four 
interfaces I use regularly, A, B, C, D, and I have the need to adapt 
A-B, A-C, B-D, C-D, with every one of these four adaptations being 
the absolute best way (as you stated all interface adaptations must 
be), then why should that be at all a problem?  Maybe sometimes someone 
will need to adapt A-D, fine -- again, no harm whatsoever, IF 
everything is as perfect as it MUST be for transitivity to apply 
unconditionally.

Put it another way: say I have the first three of these adaptations, 
only, so everything is hunky-dory.  Now I come upon a situation where I 
need C-D, fine, I add it: where's the error, if every one of the four 
adaptations is just perfect?

I admit I can't sharply follow your gyrations about what's in what 
package, who wrote what, and why the fact that interfaces and 
adaptation (particularly transitive adaptation) are NOT widespread at 
all so far (are only used by early adopters, on average heads and 
shoulders above the average Python coder) makes it MORE important to 
provide an error in a case that, by the premises, cannot be an error 
(would it be LESS important to provide the error if everybody and their 
cousin were interfacing and adapting with exhuberance...?).  All I can 
see is:

1. if an interface adapter must ABSOLUTELY be perfect, transitivity is 
fine, but the error makes no sense
2. if the error makes sense (or the assertion about less likely to be 
lossy makes any sense, etc etc), then transitivity is NOT fine -- 
adapters can be imperfect, and there is NO way to state that they are, 
one just gets an error message if one is SO DEUCEDLY LUCKY as to have 
created in the course of one's bumbling two shortest-paths of the same 
length

I suspect [2] holds.  But you're the one with experience, so if you 
stake that on [1], and the absolute best way unconditional assertion, 
then, fine, I guess, as per my previous message.  But the combination 
of absolute best way _AND_ an error when somebody adds C-D is, in my 
opinion, self-contradictory: experience or not, I can't support 
asserting something and its contrary at the same time.

then somebody is doing something redundant, and there is a possibility 
for error.  In
Not at all: each of the four above-listed adaptations may be needed to 
perform an unrelated adapt(...) operation.  How can you claim that set 
of four adaptations is REDUNDANT, when adding a FIFTH one (a direct 
A-D) would make it fine again per your rules?  This is the first time 
I've heard an implied claim that redundancy is something that can be 
eliminated by ADDING something, without taking anything away.


Personally, I disagree with having transitivity at all, unless 
perhaps it be restricted to adaptations specifically and explicitly 
stated to be perfect and lossless; PJE claims that ALL adaptations 
MUST, ALWAYS, be perfect and lossless -- essentially, it seems to 
me, he _has_ to claim that, to defend transitivity being applied 
automatically, relentlessly, NON-optionally, NON-selectively (but 
then the idea of giving an error when two or more shortest-paths have 
the same length becomes dubious).
No, it follows directly from the premise.  If adapters are non-noisy, 
why do you need more than one adapter chain of equal length between 
two points?  If you have such a condition, you
I don't NEED the chain, but I may well need each step; and by the 
premise of absolute best way which you maintain, it must be innocuous 
if the separate steps I need end up producing more than one chain -- 
what difference can it make?!

have a redundancy at the least, and more likely a programming error -- 
surely BOTH of those adapters are not correct, unless you have that 
excruciatingly-rare case I mentioned above.
Each of the FOUR adapters coded can be absolutely perfect.  Thus, the 
composite adapters which your beloved transitivity builds will also be 
perfect, and it will be absolutely harmless to pick one of them at 
random.


BTW, Microsoft's COM's interfaces ONLY have the inferior kind of 
inheritance.  You can say that interface ISub inherits from IBas: 
this means that ISub has all the same methods as IBas with the same 
signatures, plus it may have other methods; it does *NOT* mean that 
anything implementing ISub must also implement IBas, nor that a 
QueryInterface on an ISub asking for an IBas must succeed, or 
anything of that kind.  In many years of COM practice I have NEVER 
found this issue to be a limitation -- it works just fine.
I'm actually open to at least considering dropping interface 
inheritance transitivity, due to its actual problems in practice.  
Fewer than half of the interfaces in PEAK do any inheritance, so 
having to explicitly 

Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 09:30 PM 1/12/05 +0100, Alex Martelli wrote:
On 2005 Jan 12, at 20:51, Phillip J. Eby wrote:
   ...
There's a very simple reason.  If one is using only non-noisy adapters, 
there is absolutely no reason to ever define more than one adapter 
between the *same* two points.  If you do,
...but there's no harm whatsoever done, either.  If I have four interfaces 
I use regularly, A, B, C, D, and I have the need to adapt A-B, A-C, 
B-D, C-D, with every one of these four adaptations being the absolute 
best way (as you stated all interface adaptations must be), then why 
should that be at all a problem?
It isn't a problem, but *only* if A is an interface.  If it's a concrete 
class, then A-B and A-C are not perfect adapters, so it *can* make a 
difference which one you pick, and you should be explicit.

However, implementing an algorithm to ignore only interface-to-interface 
ambiguity is more complex than just hollering whenever *any* ambiguity is 
found.  Also, people make mistakes and may have declared something they 
didn't mean to.  The cost to occasionally be a bit more explicit is IMO 
outweighed by the benefit of catching bugs that might otherwise go 
unnoticed, but produce an ambiguity as a side-effect of the buggy part.

It's *possible* that you'd still catch almost as many bugs if you ignored 
pure I-to-I diamonds, but I don't feel entirely comfortable about giving up 
that extra bit of protection, especially since it would make the checker 
*more* complex to try to *not* warn about that situation.

Also, in general I'm wary of introducing non-determinism into a system's 
behavior.  I consider keeping e.g. the first path declared or the last path 
declared to be a form of non-determinism because it makes the system 
sensitive to trivial things like the order of import statements.  The 
current algorithm alerts you to this non-determinism.

Perhaps it would be simplest for Python's interface system to issue a 
warning about ambiguities, but allow execution to proceed?


(would it be LESS important to provide the error if everybody and their 
cousin were interfacing and adapting with exhuberance...?)
Only in the use case where two people might legitimately create the same 
adapter, but neither of them can stop using their adapter in favor of the 
other person's, thus forcing them to work around the error.

Or, in the case where lots of people try to define adapter diamonds and 
don't want to go to the trouble of having their program behave 
deterministically.  :)


1. if an interface adapter must ABSOLUTELY be perfect, transitivity is 
fine, but the error makes no sense
The error only makes no sense if we assume that the human(s) really *mean* 
to be ambiguous.  Ambiguity suggests, however, that something *else* may be 
wrong.


I suspect [2] holds.  But you're the one with experience, so if you stake 
that on [1], and the absolute best way unconditional assertion, then, 
fine, I guess, as per my previous message.  But the combination of 
absolute best way _AND_ an error when somebody adds C-D is, in my 
opinion, self-contradictory: experience or not, I can't support asserting 
something and its contrary at the same time.
It's not contrary; it's a warning that Are you sure you want to waste time 
writing another way to do the same thing when there's already a perfectly 
valid way to do it with a comparable number of adaptation steps 
involved?  Maybe your adapter is better-performing or less buggy in some 
way, but I'm just a machine so how would I know?  Please tell me which of 
these adapters is the *really* right one to use, thanks.  (Assuming that 
the machine is tactful enough to leave out mentioning that maybe you just 
made a mistake and declared the adapter between the wrong two points, you 
silly human you.)


How can you claim that set of four adaptations is REDUNDANT, when adding a 
FIFTH one (a direct A-D) would make it fine again per your rules?  This 
is the first time I've heard an implied claim that redundancy is something 
that can be eliminated by ADDING something, without taking anything away.
PyProtocols doesn't say the situation is redundant, it says it's 
*ambiguous*, which implies a *possible* redundancy.  I'm also saying that 
the ambiguity is nearly always (for me) an indicator of a *real* problem, 
not merely a not-so-explicit diamond.


I don't NEED the chain, but I may well need each step; and by the premise 
of absolute best way which you maintain, it must be innocuous if the 
separate steps I need end up producing more than one chain -- what 
difference can it make?!
Fair enough; however I think that in the event that the system must make 
such a choice, it must at *least* warn about non-deterministic 
behavior.  Even if you are claiming perfect adaptation, that doesn't 
necessarily mean you are correct in your claim!


Each of the FOUR adapters coded can be absolutely perfect.  Thus, the 
composite adapters which your beloved transitivity builds will also be 
perfect, 

Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Steven Bethard
On Wed, 12 Jan 2005 16:07:37 -0600, Ian Bicking [EMAIL PROTECTED] wrote:
 One case occurred to me with the discussion of strings and files, i.e.,
 adapting from a string to a file.  Let's say an IReadableFile, since
 files are too ambiguous.

 Consider the case where we are using a path object, like Jason
 Orendorff's or py.path.  It seems quite reasonable and unambiguous that
 a string could be adapted to such a path object.  It also seems quite
 reasonable and unambiguous that a path object could be adapted to a
 IReadableFile by opening the file at the given path.

This strikes me as a strange use of adaptation -- I don't see how a
string can act-as-a path object, or how a path object can act-as-a
file.  I see that you might be able to *create* a path object from-a
string, or a file from-a path object, but IMHO this falls more into
the category of object construction than object adaptation...

Are these the sorts of things we can expect people to be doing with
adaptation?  Or is in really intended mainly for the act-as-a behavior
that I had assumed...?

Steve
-- 
You can wordify anything if you just verb it.
--- Bucky Katt, Get Fuzzy
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Clark C. Evans
On Wed, Jan 12, 2005 at 04:07:37PM -0600, Ian Bicking wrote:
| A two-step adaptation encodes specific intention that it seems transitive 
| adaption would be blind to.

Exactly.  Nice example Ian. To parrot your example a bit more
concretely, the problem happens when you get two different 
adaptation paths. 

   String - PathName - File
   String - StringIO - File

Originally, Python may ship with the String-StringIO and
StringIO-File adapters pre-loaded, and if my code was reliant upon
this transitive chain, the following will work just wonderfully,

def parse(file: File):
...

parse(helloworld)

by parsing helloworld content via a StringIO intermediate object.  But
then, let's say a new component pathutils registers another adapter pair:

   String-PathName and PathName-File

This ambiguity causes a few problems:

  - How does one determine which adapter path to use?
  - If a different path is picked, what sort of subtle bugs occur?
  - If the default path isn't what you want, how do you specify 
the other path?
 
I think Phillip's suggestion is the only resonable one here, ambiguous
cases are an error; ask the user to register the adapter they need, or
do a specific cast when calling parse().

| As I think these things through, I'm realizing that registered 
| adaptators really should be 100% accurate (i.e., no information loss, 
| complete substitutability), because a registered adapter that seems 
| pragmatically useful in one place could mess up unrelated code, since 
| registered adapters have global effects.

I think this isn't all that useful; it's unrealistic to assume that
adapters are always perfect.   If transitive adaptation is even
permitted, it should be unambiguous.  Demanding that adaption is
100% perfect is a matter of perspective.  I think String-StringIO
and StringIO-File are perfectly pure.

| Perhaps transitivity seems dangerous because that has the potential to 
| dramatically increase the global effects of those registered adapters.

I'd prefer,
  
1. adaptation to _not_ be transitive (be explicit)

2. a simple mechanism for a user to register an explicit
   adaptation path from a source to a destination:

   adapt.path(String,PathName,File)

   to go from String-File, using PathName as an intermediate.

3. an error message, AdaptationError, to list all possible
   adaptation paths:

  Could not convert 'String' object to 'File' beacuse
  there is not a suitable adapter.  Please consider an
  explicit conversion, or register a composite adapter
  with one of the following paths:

 adapt.path(String,PathName,File)
 adapt.path(String,StringIO,File)

3. raise an exception when _registering_ a 'path' which would
   conflict with any existing adapter:
   
  Could not complete adapt.path(String,PathName,File) 
   since an existing direct adapter from String to Path
   already exists.
   
  Could not complete adapt.path(String,PathName,File)
   since an existing path String-StringIO-File is
   already registered.

I'd rather have the latter error occur when importing modules
rather than at run-time.  This way, the exception is pinned on
the correct library developer.

Best,

Clark
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 04:07 PM 1/12/05 -0600, Ian Bicking wrote:
It also seems quite reasonable and unambiguous that a path object could be 
adapted to a IReadableFile by opening the file at the given path.
Not if you think of adaptation as an as-a relationship, like using a 
screwdriver as a hammer (really an IPounderOfNails, or some such).  It 
makes no sense to use a path as a readable file, so this particular 
adaptation is bogus.


The problem is with the first example, where two seemingly innocuous 
adapters (string-path, path-IReadableFile) allow a new adaptation that 
could cause all sorts of problems (string-IReadableFile).
Two problems with this thought:
1) path-IReadableFile is bogus
2) even if you had path-IReadableFile, you're not broken unless you extend 
transitivity to pass through concrete target types (which I really don't 
recommend)


Ideally, if I had code that was looking for a file object and I wanted to 
accept filenames, I'd want to try to adapt to file, and if that failed I'd 
try to adapt to the path object and then from there to the file object.
There are two reasonable ways to accomplish this.  You can have code that 
expects an open stream -- in which case what's the harm in wrapping 
open() arount the value you pass if you want it to be opened?  OR, you 
can have code that expects an openable stream, in which case you can pass 
it any of these:

1. an already-open stream (that then adapts to an object with a trivial 
'open()' method),
2. a path object that implements openable stream
3. a string that adapts to openable stream by conversion to a path object

The only thing you can't implicitly pass in that case is a 
string-to-be-a-StringIO; you have to explicitly make it a StringIO.

In *either* case, you can have a string adapt to either a path object or to 
a StringIO; you just can't have both then come back to a common interface.


As I think these things through, I'm realizing that registered adaptators 
really should be 100% accurate (i.e., no information loss, complete 
substitutability), because a registered adapter that seems pragmatically 
useful in one place could mess up unrelated code, since registered 
adapters have global effects.  Perhaps transitivity seems dangerous 
because that has the potential to dramatically increase the global effects 
of those registered adapters.
However, if you:
1) have transitivity only for interface-to-interface relationships 
(allowing only one class-to-interface link at the start of the path), and

2) use adaptation only for as a relationships, not to represent 
operations on objects

you avoid these problems.  For example, avoiding the one adapter you 
presented that's not as a, the adapter diamond becomes a triangle.

The longer the discussion goes on, however, the more I realize that like 
the internet, transitivity depends on the continued goodwill of your 
neighbors, and it only takes one fool to ruin things for a lot of 
people.  On the other hand, I also hate the idea of having to kludge 
workarounds like the one James Knight was doing, in order to get a simple 
adaptation to work.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Ian Bicking
Phillip J. Eby wrote:
At 04:07 PM 1/12/05 -0600, Ian Bicking wrote:
It also seems quite reasonable and unambiguous that a path object 
could be adapted to a IReadableFile by opening the file at the given 
path.

Not if you think of adaptation as an as-a relationship, like using a 
screwdriver as a hammer (really an IPounderOfNails, or some such).  It 
makes no sense to use a path as a readable file, so this particular 
adaptation is bogus.
I started to realize that in a now-aborted reply to Steven, when my 
defense of the path-IReadableFile adaptation started making less sense. 
 It's *still* not intuitively incorrect to me, but there's a couple 
things I can think of...

(a) After you adapted the path to the file, and have a side-effect of 
opening a file, it's unclear who is responsible for closing it.
(b) The file object clearly has state the path object doesn't have, like 
a file position.
(c) You can't  go adapting the path object to a file whenever you 
wanted, because of those side effects.

So those are some more practical reasons that it *now* seems bad to me, 
but that wasn't my immediate intuition, and I could have happily written 
out all the necessary code without countering that intuition.  In fact, 
I've misused adaptation before (I think) though in different ways, and 
it those mistakes haven't particularly improved my intuition on the 
matter.  If you can't learn from mistakes, how can you learn?

One way is with principles and rules, even if they are flawed or 
incomplete.  Perhaps avoiding adaptation diamonds is one such rule; it 
may not be necessarily and absolutely a bad thing that there is a 
diamond, but it is often enough a sign of problems elsewhere that it may 
be best to internalize that belief anyway.  Avoiding diamonds alone 
isn't enough of a rule, but maybe it's a start.

--
Ian Bicking  /  [EMAIL PROTECTED]  / http://blog.ianbicking.org
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
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 

Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 16:34, Phillip J. Eby wrote:
   ...
Anyway, I agree that your version of the code should be used to form 
the reference implementation, since the purpose of the reference 
implementation is to show the complete required semantics.
Great, one point at last on which we fully agree -- thanks Armin!-)
I was waiting for BDFL feedback before editing the PEP again, but if 
none is forthcoming I guess at some point I'll go ahead and at least to 
the edits that are apparently not controversial, like this one.  I'd 
like to have a summary of controversial points and short pro and con 
args, too, but I'm not unbiased enough to write it all by myself...;-)

Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Michael Chermside
Phillip:

I think you must inhabit a far more perfect world than I do.

You say, for instance, that:
 ...-1 if this introduces a performance penalty [...] just to
 support people who want to create deliberate Liskov violations.
 I personally don't think that we should pander to Liskov
 violators

... but in my world, people violate Liskov all the time, even
in languages that attempt (unsuccessfully) to enforce it. [1]

You say that:
 I think one should adapt primarily to interfaces, and
 interface-to-interface adaptation should be reserved for
 non-lossy, non-noisy adapters.

... but in my world, half the time I'm using adaptation to
correct for the fact that someone else's poorly-written
code requests some class where it should have just used
an interface.

You seem to inhabit a world in which transitivity of adaptation
can be enforced. But in my world, people occasionally misuse
adaptation because they think they know what they're doing
or because they're in a big hurry and it's the most convenient
tool at hand.

I wish I lived in your world, but I don't.

-- Michael Chermside

[1] - Except for Eiffel. Eiffel seems to do a pretty good job
   of enforcing it.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 09:27 AM 1/11/05 -0800, Michael Chermside wrote:
Phillip:
I think you must inhabit a far more perfect world than I do.
You say, for instance, that:
 ...-1 if this introduces a performance penalty [...] just to
 support people who want to create deliberate Liskov violations.
 I personally don't think that we should pander to Liskov
 violators
I've since dropped both the performance objection and the objection to 
supporting Liskov violation; in a more recent post I've proposed an 
alternative algorithm for allowing it, that has a simpler implementation.


You say that:
 I think one should adapt primarily to interfaces, and
 interface-to-interface adaptation should be reserved for
 non-lossy, non-noisy adapters.
... but in my world, half the time I'm using adaptation to
correct for the fact that someone else's poorly-written
code requests some class where it should have just used
an interface.
PEP 246 adaptation?  Or are you talking about some other language?  (I ask 
out of curiosity.)

I agree that if it's possible to adapt to concrete types, people will do 
so.  However, I think we all agree that this isn't a great idea and should 
still be considered bad style.  That's not the same thing as saying it 
should be forbidden, and I haven't said it should be forbidden.


You seem to inhabit a world in which transitivity of adaptation
can be enforced. But in my world, people occasionally misuse
adaptation because they think they know what they're doing
or because they're in a big hurry and it's the most convenient
tool at hand.
How is this different from abuse of *any* language feature that you're then 
forced to work around?  Are you saying we should not provide a feature 
because *some* people will abuse the feature?  I don't understand.

If you allow interface inheritance, you're just as susceptible to an 
invalid adaptation path, and in my experience this is more likely to bite 
you unintentionally, mainly because interface inheritance works differently 
than class inheritance (which of course is used more often).  Do you want 
to prohibit interface inheritance, too?

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Clark C. Evans
On Tue, Jan 11, 2005 at 12:54:36PM -0500, Phillip J. Eby wrote:
| * Replacing LiskovViolation is possible by dropping type/isinstance 
| checks from adapt(), and adding an isinstance check to 
| object.__conform__; Liskov violators then override __conform__ in their 
| class to return None when asked to conform to a protocol they wish to 
| reject, and return super().__conform__ for all other cases.  This 
| achieves your use case while simplifying both the implementation and the 
| usage.

I'd rather not assume that class inheritance implies substitutability,
unless the class is marked as an interface (assuming that one 
doesn't have interfaces).  I'd like it to be explicit -- a bit of a
nudge to remind a developer to verify substitutability is a good
thing. In this scenerio, a LiskovViolation exception isn't needed
(aside, I don't see the rationale for the exception: to prevent
third party adapters?). Could we make a boilerplate __conform__
which enables class-based substitutability a well-known decorator?

| * In my experience, incorrectly deriving an interface from another is the 
| most common source of unintended adaptation side-effects, not adapter 
| composition

It'd be nice if interfaces had a way to specify a test-suite that
could be run against a component which claims to be compliant.   For
example, it could provide invalid inputs and assert that the proper
errors are returned, etc.

Best,

Clark


-- 
Clark C. Evans  Prometheus Research, LLC.
http://www.prometheusresearch.com/
o   office: +1.203.777.2550 
  ~/ ,  mobile: +1.203.444.0557 
 //
((   Prometheus Research: Transforming Data Into Knowledge
 \\  ,
   \/- Research Exchange Database
   /\- Survey  Assessment Technologies
   ` \   - Software Tools for Researchers
~ *
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Michael Chermside
David Ascher writes:
 Terminology point: I know that LiskovViolation is technically correct,
 but I'd really prefer it if exception names (which are sometimes all
 users get to see) were more informative for people w/o deep technical
 background.  Would that be possible?

I don't see how. Googling on Liskov immediately brings up clear
and understandable descriptions of the principle that's being violated.
I can't imagine summarizing the issue more concisely than that! What
would you suggest? Including better explanations in the documentation
is a must, but LiskovViolation in the exception name seems unbeatably
clear and concise.

-- Michael Chermside

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 01:50 PM 1/11/05 -0500, Clark C. Evans wrote:
On Tue, Jan 11, 2005 at 12:54:36PM -0500, Phillip J. Eby wrote:
| * Replacing LiskovViolation is possible by dropping type/isinstance
| checks from adapt(), and adding an isinstance check to
| object.__conform__; Liskov violators then override __conform__ in their
| class to return None when asked to conform to a protocol they wish to
| reject, and return super().__conform__ for all other cases.  This
| achieves your use case while simplifying both the implementation and the
| usage.
I'd rather not assume that class inheritance implies substitutability,
Hm, you should take that up with Alex then, since that is what his current 
PEP 246 draft does.  :)  Actually, the earlier drafts did that too, so I'm 
not sure why you want to change this now.

What I've actually suggested here actually allows for 
inheritance=substitutability as the default, but also makes it trivially 
changeable for any given inheritance hierarchy by overriding __conform__ at 
the base of that hierarchy, and without introducing a special exception 
class to do it.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 09:23 PM 1/11/05 +0100, Alex Martelli wrote:
Is the concept of *PRAGMATICS* so deucedly HARD for all of your eggheads?!
Hmm.  Pot, meet kettle.  :)

Yes, you're ALLOWED to stuff with NULL any field that isn't explicitly 
specified as NOT NULL.

But you should ONLY do so when the information is REALLY missing, NOT when 
you've lost it along the way because you've implemented adapter-chain 
transitivity: dropping information which you COULD have preserved with a 
bit more care (==without transitivity) is a violation of PRAGMATICS, of 
the BEST-EFFORT implication, just as it would be to drop packets once in a 
while in a TCP/IP stack due to some silly programming bug which was passed 
silently.
This is again a misleading analogy.  You are comparing end-to-end with 
point-to-point.  I am saying that if you have a point-to-point connection 
that drops all packets of a particular kind, you should not put it into 
your network, unless you know that an alternate route exists that can 
ensure those packets get through.  Otherwise, you are breaking the network.

Thus, I am saying that PRAGMATICALLY, it is silly to create a cable that 
drops all ACK packets, for example, and then plug it into your 
network.  And especially, it's silly to turn around that as a reason that 
one should only use end-to-end leased lines, because that packet forwarding 
business is dangerously unreliable!

As far as I can tell, you are arguing that you should never use packet 
forwarding for communication, because somebody might have a router 
somewhere that drops packets.  While I am arguing that if a router is known 
to drop packets incorrectly, the router is broken and should be removed 
from the network, or else bypassed via another route.  And, in the cases 
where you have a leased line direct from point A to point B, your routers 
should be smart enough to use that route in place of forwarding from A to C 
to D to B, or whatever.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 22:08, Phillip J. Eby wrote:
   ...
Yes, you're ALLOWED to stuff with NULL any field that isn't 
explicitly specified as NOT NULL.

But you should ONLY do so when the information is REALLY missing, NOT 
when you've lost it along the way because you've implemented 
adapter-chain transitivity: dropping information which you COULD have 
preserved with a bit more care (==without transitivity) is a 
violation of PRAGMATICS, of the BEST-EFFORT implication, just as it 
would be to drop packets once in a while in a TCP/IP stack due to 
some silly programming bug which was passed silently.
This is again a misleading analogy.  You are comparing end-to-end with 
point-to-point.  I am saying that if you have a point-to-point 
connection that drops all packets of a particular kind, you should not 
put it into your network, unless you know that an alternate route 
exists that can ensure those packets get through.  Otherwise, you are 
breaking the network.
But adaptation is not transmission!  It's PERFECTLY acceptable for an 
adapter to facade: to show LESS information in the adapted object than 
was in the original.  It's PERFECTLY acceptable for an adapter to say 
this piece information is not known when it's adapting an object for 
which that information, indeed, is not known.  It's only CONJOINING the 
two perfectly acceptable adapters, as transitivity by adapter chain 
would do automatically, that you end up with a situation that is 
pragmatically undesirable: asserting that some piece of information is 
not known, when the information IS indeed available -- just not by the 
route automatically taken by the transitivity-system.

What happened here is not that either of the adapters registered is 
wrong: each does its job in the best way it can.  The programming 
error, which transitivity hides (degrading the quality of information 
resulting from the system -- a subtle kind of degradation that will be 
VERY hard to unearth), is simply that the programmer forgot to register 
the direct adapter.  Without transitivity, the programmer's mistake 
emerges easily and immediately; transitivity hides the mistake.

By imposing transitivity, you're essentially asserting that, if a 
programmer forgets to code and register an A - C direct adapter, this 
is never a problem, as long as A - B and B - C adapters are 
registered, because A - B - C will give results just as good as the 
direct A - C would have, so there's absolutely no reason to trouble 
the programmer about the trivial detail that transitivity is being 
used.

At the same time, if I understand correctly, you're ALSO saying that if 
two other adapters exist, A - Z and Z - C, *THEN* it's an error, 
because you don't know when adapting A - C whether to go via B or via 
Z.  Well, if you consistently believe what I state in the previous 
paragraph, then this is just weird: since you're implicitly asserting 
that any old A-?-C transitive adaptation is just as good as a direct 
A-C, why should you worry about there being more than one such 2-step 
adaptation available?  Roll the dice to pick one and just proceed.

Please note that in the last paragraph I'm mostly trying to reason by 
absurd: I do NOT believe one can sensibly assert in the general case 
that A-?-C is just as good as A-C, without imposing FAR stronger 
constraints on adaptation that we possibly can (QI gets away with it 
because, designed from scratch, it can and does impose such 
constraints, essentially that all interfaces belong to ONE single 
object -- no independent 3rd party adaptation, which may be a bigger 
loss than the constraints gain, actually).

I'm willing to compromise to the extent of letting any given adaptation 
somehow STATE, EXPLICITLY, this adaptation is lossless and perfect, 
and can be used as a part of transitive chains of adaptation without 
any cost whatsoever.  If we do that, though, the adaptation system 
should trust this assertion, so if there are two possibilities of equal 
minimal length, such as A-B-C or A-Z-C, with all the steps being 
declared lossless and perfect, then it SHOULD just pick one by whatever 
criterion, since both will be equally perfect anyway -- so maybe my 
reasoning by absurd wasn't totally absurd after all;-).

Would this compromise be acceptable to you?
Alex
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Clark C. Evans
On Tue, Jan 11, 2005 at 03:30:19PM -0500, Phillip J. Eby wrote:
| Clark said he didn't want to assume substitutability; I was pointing out 
| that he could choose to not assume that, if he wished, by implementing an 
| appropriate __conform__ at the base of his hierarchy. 

Oh, that's sufficient.  If someone making a base class wants to assert
that derived classes should check compliance (rather than having it
automagic), then they can do this.  Good enough!

| I don't agree with Clark's use case, but my 
| proposal supports it as a possibility, and yours does not.

It was a straw-man; and I admit, not a particularly compelling one.

| To implement a Liskov violation with my proposal, you do exactly the same 
| as with your proposal, *except* that you can simply return None instead 
| of raising an exception, and the logic for adapt() is more 
| straightforward.

I think I prefer just returning None rather than raising a
specific exception.  The semantics are different: None implies that
other adaptation mechanisms (like a registry) could be tried, while
LiskovException implies that processing halts and no further 
adaptation techniques are to be used.  In this case, None is 
the better choice for this particular case since it would enable
third-parties to register a wrapper.

Overall, I think both you and Alex are now proposing essentially
the same thing... no?

Best,

Clark

-- 
Clark C. Evans  Prometheus Research, LLC.
http://www.prometheusresearch.com/
o   office: +1.203.777.2550 
  ~/ ,  mobile: +1.203.444.0557 
 //
((   Prometheus Research: Transforming Data Into Knowledge
 \\  ,
   \/- Research Exchange Database
   /\- Survey  Assessment Technologies
   ` \   - Software Tools for Researchers
~ *
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 06:38 PM 1/11/05 -0500, Clark C. Evans wrote:
| To implement a Liskov violation with my proposal, you do exactly the same
| as with your proposal, *except* that you can simply return None instead
| of raising an exception, and the logic for adapt() is more
| straightforward.
I think I prefer just returning None rather than raising a
specific exception.  The semantics are different: None implies that
other adaptation mechanisms (like a registry) could be tried, while
LiskovException implies that processing halts and no further
adaptation techniques are to be used.  In this case, None is
the better choice for this particular case since it would enable
third-parties to register a wrapper.
Overall, I think both you and Alex are now proposing essentially
the same thing... no?
Yes; I'm just proposing shuffling the invocation of things around a bit in 
order to avoid the need for an exception, and in the process increasing the 
number of possible customizations a bit.

Not that I care about those customizations as such; I just would like to 
simplify the protocol.  I suppose there's some educational benefit in 
making somebody explicitly declare that they're a Liskov violator, but it 
seems that if we're going to support it, it should be simple.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Raymond Hettinger
 Thus, my argument is that an adapter like this should never be made
part
 of
 the adapter system, even if there's no transitivity.  However, if you
 agree
 that such an adapter shouldn't be implicit, then it logically follows
that
 there is no problem with allowing transitivity, except of course that
 people may sometimes break the rule.

At some point, the PEP should be extended to include a list of best
practices and anti-patterns for using adapters.  I don't find issues of
transitivity and implicit conversion to be immediately obvious.

Also, it is not clear to me how or if existing manual adaption practices
should change.  For example, if I need a file-like interface to a
string, I currently wrap it with StringIO.  How will that change it the
future?  By an explicit adapt/conform pair?  Or by strings knowing how
to conform to file-like requests?


Raymond Hettinger

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] PEP 246, redux

2005-01-11 Thread Roeland Rengelink
I'm trying to understand the relation between Guido's posts on optional 
 static typing and PEP 245 (interfaces) and 246 (adaptation). I have a 
 couple of questions

PEP 245 proposes to introduce a fundamental distinction between type and 
 interface. However, 245 only introduces a syntax for interfaces, and 
says very little about the semantics of interfaces. (Basically only that 
 if X implements Y then implements(X, Y) will return True). The 
semantics of interfaces are currently only implied by PEP 246, and by 
Guido's  posts referring to 246.

Unfortunately PEP 246 explicitly refuses to decide that protocols are 
245-style interfaces. Therefore, it is not clear to me how acceptance of 
 245 would impact on 246?  Specifically, what would be the difference 
between:

x = adapt(obj, a_245_style_interface)
x = adapt(obj, a_protocol_type)
and, if there is no difference, what would the use-case of interfaces be?
Put another way: explicit interfaces and adaptation based typing seem to 
 be about introducing rigor (dynamic, not static) to Python. Yet, PEP 
245 and 246 seems to go out of their way to give interfaces and 
adaptation as little baggage as possible. So, where is the rigor going 
to come from?

On the one hand this seems very Pythonic - introduce a new feature with 
as little baggage as possible, and see where it evolves from there. Let 
the rigor flow, not from the restrictions of the language, but from the 
 expressive power of the language.

On the other hand: why not, at least:
- explore in 245 how the semantics of interfaces might introduce rigor 
into the language. It would be particularly illuminating to find out in 
what way implementing an interface differs from deriving from an ABC 
and  in what way an interface hierarchy differs semantically from a 
hierarchy  of ABCs

- rewrite 246 under the assumption that 245 (including semantics) has 
been accepted

I would volunteer, but, for those of you who hadn't noticed yet, I don't 
know what I'm talking about.

Cheers,
Roeland Rengelink

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 07:52 PM 1/11/05 -0500, Raymond Hettinger wrote:
Also, it is not clear to me how or if existing manual adaption practices
should change.  For example, if I need a file-like interface to a
string, I currently wrap it with StringIO.  How will that change it the
future?  By an explicit adapt/conform pair?  Or by strings knowing how
to conform to file-like requests?
The goal here is to be able to specify that a function parameter takes, 
e.g. a readable stream, and that you should be able to either explicitly 
wrap in a StringIO to satisfy this, or *possibly* that you be able to just 
pass a string and have it work automatically.

If the latter is the case, there are a variety of possible ways it might 
work.  str.__conform__ might recognize the readable stream interface, or 
the __adapt__ method of the readable stream interface could recognize 
'str'.  Or, Alex's new proposed global type registry might contain an entry 
for 'str,readableStream'.  Which of these is the preferred scenario very 
much depends on a lot of things, like who defined the readable stream 
interface, and whether anybody has registered an adapter for it!

PyProtocols tries to answer this question by allowing you to register 
adapters with interfaces, and then the interface's __adapt__ method will do 
the actual adaptation.  Zope does something similar, at least in that it 
uses the interface's __adapt__ method, but that method actually uses a 
global registry.

Neither PyProtocols nor Zope make much use of actually implementing 
hand-coded __conform__ or __adapt__ methods, as it's too much trouble for 
something that's so inherently declarative anyway, and only the creator of 
the object class or the interface's type have any ability to define 
adapters that way.  Given that built-in types are often handy sources of 
adaptation (e.g. str-to-StringIO in your example), it isn't practical in 
present-day Python to add a __conform__ method to the str type!

Thus, in the general case it just seems easier to use a per-interface or 
global registry for most normal adaptation, rather than using 
__conform__.  However, having __conform__ exist is a nice out for 
implementing unusual custom requirements (like easy dynamic conformance), 
so I don't think it should be removed.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] PEP 246, redux

2005-01-10 Thread Alex Martelli
I had been promising to rewrite PEP 246 to incorporate the last several 
years' worth of discussions c about it, and Guido's recent stop the 
flames artima blog post finally pushed me to complete the work.  
Feedback is of course welcome, so I thought I had better repost it 
here, rather than relying on would-be commenters to get it from CVS... 
I'm also specifically CC'ing Clark, the co-author, since he wasn't 
involved in this rewrite and of course I owe it to him to change or 
clearly attribute to myself anything he doesn't like to have under his 
own name!

Thanks,
Alex
PEP: 246
Title: Object Adaptation
Version: $Revision: 1.6 $
Author: [EMAIL PROTECTED] (Alex Martelli),
[EMAIL PROTECTED] (Clark C. Evans)
Status: Draft
Type: Standards Track
Created: 21-Mar-2001
Python-Version: 2.5
Post-History: 29-Mar-2001, 10-Jan-2005
Abstract
This proposal puts forth an extensible cooperative mechanism for
the adaptation of an incoming object to a context which expects an
object supporting a specific protocol (say a specific type, class,
or interface).
This proposal provides a built-in adapt function that, for any
object X and any protocol Y, can be used to ask the Python
environment for a version of X compliant with Y.  Behind the
scenes, the mechanism asks object X: Are you now, or do you know
how to wrap yourself to provide, a supporter of protocol Y?.
And, if this request fails, the function then asks protocol Y:
Does object X support you, or do you know how to wrap it to
obtain such a supporter?  This duality is important, because
protocols can be developed after objects are, or vice-versa, and
this PEP lets either case be supported non-invasively with regard
to the pre-existing component[s].
Lastly, if neither the object nor the protocol know about each
other, the mechanism may check a registry of adapter factories,
where callables able to adapt certain objects to certain protocols
can be registered dynamically.  This part of the proposal is
optional: the same effect could be obtained by ensuring that
certain kinds of protocols and/or objects can accept dynamic
registration of adapter factories, for example via suitable custom
metaclasses.  However, this optional part allows adaptation to be
made more flexible and powerful in a way that is not invasive to
either protocols or other objects, thereby gaining for adaptation
much the same kind of advantage that Python standard library's
copy_reg module offers for serialization and persistence.
This proposal does not specifically constrain what a protocol
_is_, what compliance to a protocol exactly _means_, nor what
precisely a wrapper is supposed to do.  These omissions are
intended to leave this proposal compatible with both existing
categories of protocols, such as the existing system of type and
classes, as well as the many concepts for interfaces as such
which have been proposed or implemented for Python, such as the
one in PEP 245 [1], the one in Zope3 [2], or the ones discussed in
the BDFL's Artima blog in late 2004 and early 2005 [3].  However,
some reflections on these subjects, intended to be suggestive and
not normative, are also included.
Motivation
Currently there is no standardized mechanism in Python for
checking if an object supports a particular protocol.  Typically,
existence of certain methods, particularly special methods such as
__getitem__, is used as an indicator of support for a particular
protocol.  This technique works well for a few specific protocols
blessed by the BDFL (Benevolent Dictator for Life).  The same can
be said for the alternative technique based on checking
'isinstance' (the built-in class basestring exists specifically
to let you use 'isinstance' to check if an object is something
like a string).  Neither approach is easily and generally
extensible to other protocols, defined by applications and third
party frameworks, outside of the standard Python core.
Even more important than checking if an object already supports a
given protocol can be the task of obtaining a suitable adapter
(wrapper or proxy) for the object, if the support is not already
there.  For example, a string does not support the file protocol,
but you can wrap it into a StringIO instance to obtain an object
which does support that protocol and gets its data from the string
it wraps; that way, you can pass the string (suitably wrapped) to
subsystems which require as their arguments objects that are
readable as files.  Unfortunately, there is currently no general,
standardized way to automate this extremely important kind of
adaptation by wrapping operations.
Typically, today, when you pass objects to a context expecting a
particular protocol, either the object knows about the context and
provides its own 

Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Guido van Rossum
 I had been promising to rewrite PEP 246 to incorporate the last several
 years' worth of discussions c about it, and Guido's recent stop the
 flames artima blog post finally pushed me to complete the work.
 Feedback is of course welcome, so I thought I had better repost it
 here, rather than relying on would-be commenters to get it from CVS...

Thanks for doing this, Alex! I yet have to read the whole thing [will
attempt do so later today] but the few snippets I caught make me feel
this is a big step forward.

I'm wondering if someone could do a similar thing for PEP 245,
interfaces syntax? Alex hinted that it's a couple of rounds behind the
developments in Zope and Twisted. I'm personally not keen on needing
*two* new keywords (interface and implements) so I hope that whoever
does the rewrite could add a section on the advantages and
disadvantages of the 'implements' keyword (my simplistic alternative
proposal is to simply include interfaces in the list of bases in the
class statement; the metaclass can then sort it out).

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Alex Martelli
On 2005 Jan 10, at 18:43, Phillip J. Eby wrote:
   ...
At 03:42 PM 1/10/05 +0100, Alex Martelli wrote:
The fourth case above is subtle.  A break of substitutability can
occur when a subclass changes a method's signature, or restricts
the domains accepted for a method's argument (co-variance on
arguments types), or extends the co-domain to include return
values which the base class may never produce (contra-variance
on return types).  While compliance based on class inheritance
_should_ be automatic, this proposal allows an object to signal
that it is not compliant with a base class protocol.
-1 if this introduces a performance penalty to a wide range of 
adaptations (i.e. those using abstract base classes), just to support 
people who want to create deliberate Liskov violations.  I personally 
don't think that we should pander to Liskov violators, especially 
since Guido seems to be saying that there will be some kind of 
interface objects available in future Pythons.
If interfaces can ensure against Liskov violations in instances of 
their subclasses, then they can follow the case (a) fast path, sure.  
Inheriting from an interface (in Guido's current proposal, as per his 
Artima blog) is a serious commitment from the inheritor's part; 
inheriting from an ordinary type, in real-world current practice, need 
not be -- too many cases of assumed covariance, for example, are around 
in the wild, to leave NO recourse in such cases and just assume 
compliance.


Just like any other special method in today's Python, __conform__
is meant to be taken from the object's class, not from the object
itself (for all objects, except instances of classic classes as
long as we must still support the latter).  This enables a
possible 'tp_conform' slot to be added to Python's type objects in
the future, if desired.
One note here: Zope and PEAK sometimes use interfaces that a function 
or module may implement.  PyProtocols' implementation does this by 
adding a __conform__ object to the function's dictionary so that the 
function can conform to a particular signature.  If and when 
__conform__ becomes tp_conform, this may not be necessary any more, at 
least for functions, because there will probably be some way for an 
interface to tell if the function at least conforms to the appropriate 
signature.  But for modules this will still be an issue.

I am not saying we shouldn't have a tp_conform; just suggesting that 
it may be appropriate for functions and modules (as well as classic 
classes) to have their tp_conform delegate back to 
self.__dict__['__conform__'] instead of a null implementation.
I have not considered conformance of such objects as functions or 
modules; if that is important, I need to add it to the reference 
implementation in the PEP.  I'm reluctant to just get __conform__ from 
the object, though; it leads to all sort of issues with a *class* 
conforming vs its *instances*, etc.  Maybe Guido can Pronounce a little 
on this sub-issue...


I don't see the benefit of LiskovViolation, or of doing the exact type 
check vs. the loose check.  What is the use case for these?  Is it to 
allow subclasses to say, Hey I'm not my superclass?  It's also a bit 
confusing to say that if the routines raise any other exceptions 
they're propagated.  Are you saying that LiskovViolation is *not* 
propagated?
Indeed I am -- I thought that was very clearly expressed!  
LiskovViolation means to skip the loose isinstance check, but it STILL 
allows explicitly registered adapter factories a chance (if somebody 
registers such an adapter factory, presumably they've coded a suitable 
adapter object type to deal with some deuced Liskov violation, see...). 
 On the other hand, if some random exception occurs in __conform__ or 
__adapt__, that's a bug somewhere, so the exception propagates in order 
to help debugging.  The previous version treated TypeError specially, 
but I think (on the basis of just playing around a bit, admittedly) 
that offers no real added value and sometimes will hide bugs.


If none of the first four mechanisms worked, as a last-ditch
attempt, 'adapt' falls back to checking a registry of adapter
factories, indexed by the protocol and the type of `obj', to meet
the fifth case.  Adapter factories may be dynamically registered
and removed from that registry to provide third party adaptation
of objects and protocols that have no knowledge of each other, in
a way that is not invasive to either the object or the protocols.
This should either be fleshed out to a concrete proposal, or dropped.  
There are many details that would need to be answered, such as whether 
type includes subtypes and whether it really means type or 
__class__.  (Note that isinstance() now uses __class__, allowing proxy 
objects to lie about their class; the adaptation system should support 
this too, and both the Zope and PyProtocols interface systems and 

Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Michael Hudson
Alex Martelli [EMAIL PROTECTED] writes:

 I didn't know about the let the object lie quirk in isinstance.  If
 that quirk is indeed an intended design feature, rather than an
 implementation 'oops', it might perhaps be worth documenting it more
 clearly; I do not find that clearly spelled out in the place I'd
 expect it to be, namely
 http://docs.python.org/lib/built-in-funcs.html under 'isinstance'.

Were you not at the PyPy sprint where bugs in some __getattr__ method
caused infinite recursions on the isinstance's code attempting to
access __class__?  The isinstance code then silently eats the error,
so we had (a) a massive slowdown and (b) isinstance failing in an
impossible way.  A clue was that if you ran the code on OS X with
its silly default stack limits the code dumped core instead of going
slowly insane.

This is on quirk I'm not likely to forget in a hurry...

Cheers,
mwh

-- 
  If trees could scream, would we be so cavalier about cutting them
  down? We might, if they screamed all the time, for no good reason.
-- Jack Handey
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Clark C. Evans
On Mon, Jan 10, 2005 at 01:34:59PM -0500, Phillip J. Eby wrote:
| The performance penalty I was talking about was for using an abstract 
| base class, in a subclass with a __conform__ method for conformance to 
| other protocols.  In this case, __conform__ will be uselessly called 
| every time the object is adapted to the abstract base class.

*nod*

If this proposal was packaged with an interface mechanism, would
this address your concern?  In this scenerio, there are two cases:

  - Older classes will most likely not have a __conform__ method.
  - Newer classes will use the 'interface' mechanism.

In this scenerio, there isn't a performance penalty for the 
usual case; and for migration purposes, a flag could be added
to disable the checking.

Best,

Clark
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Michel Pelletier
On Monday 10 January 2005 09:58 am, [EMAIL PROTECTED] wrote:

 Message: 3
 Date: Mon, 10 Jan 2005 07:46:39 -0800
 From: Guido van Rossum [EMAIL PROTECTED]
 Subject: Re: [Python-Dev] PEP 246, redux
 To: Alex Martelli [EMAIL PROTECTED]
 Cc: Clark C.Evans [EMAIL PROTECTED], Python Dev
   python-dev@python.org
 Message-ID: [EMAIL PROTECTED]
 Content-Type: text/plain; charset=US-ASCII

  I had been promising to rewrite PEP 246 to incorporate the last several
  years' worth of discussions c about it, and Guido's recent stop the
  flames artima blog post finally pushed me to complete the work.
  Feedback is of course welcome, so I thought I had better repost it
  here, rather than relying on would-be commenters to get it from CVS...

 Thanks for doing this, Alex! I yet have to read the whole thing [will
 attempt do so later today] but the few snippets I caught make me feel
 this is a big step forward.

Me too!  I didn't realize it the first time 246 came around how important 
adaptation was and how interfaces just aren't as useful without it.


 I'm wondering if someone could do a similar thing for PEP 245,
 interfaces syntax? Alex hinted that it's a couple of rounds behind the
 developments in Zope and Twisted. 

Nothing implements 245, which is just about the syntax, I intended to write 
another PEP describing an implementation, at the time Jim's original 
straw-man; which I'm glad I didn't do as it would have been a waste of time.  
Had I written that document, then it would be a copule of rounds behind Zope 
and Twisted.  But as it stands now nothing need be based on 245.

 I'm personally not keen on needing 
 *two* new keywords (interface and implements) so I hope that whoever
 does the rewrite could add a section on the advantages and
 disadvantages of the 'implements' keyword (my simplistic alternative
 proposal is to simply include interfaces in the list of bases in the
 class statement; the metaclass can then sort it out).

I like implements, but any spelling works for me.  implements strikes me as 
an elegant counterpart to interface and risks minimal breakage.  Can we 
still import and say implements() for b/w compatibility and for those of us 
who do want an explicit statement like that?

-Michel
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Phillip J. Eby
At 04:16 PM 1/10/05 -0800, Michel Pelletier wrote:
 From: Guido van Rossum [EMAIL PROTECTED]
 Subject: Re: [Python-Dev] PEP 246, redux

 I'm wondering if someone could do a similar thing for PEP 245,
 interfaces syntax? Alex hinted that it's a couple of rounds behind the
 developments in Zope and Twisted.
Nothing implements 245, which is just about the syntax,
The comment Guido's alluding to was mine; I was referring to PEP 245's use 
of '__implements__', and the difference between what a class implements 
and an instance provides.  Twisted and Zope's early implementations just 
looked for ob.__implements__, which leads to issues with distinguishing 
between what a class provides from what its instances provide.

So, I was specifically saying that this aspect of PEP 245 (and Guido's 
basing a Python interface implementation thereon) should be re-examined in 
the light of current practices that avoid this issue.  (I don't actually 
know what Zope currently does; it was changed after I had moved to using 
PyProtocols.  But the PyProtocols test suite tests that Zope does in fact 
have correct behavior for instances versus classes, because it's needed to 
exercise the PyProtocols-Zope interop tests.)


I like implements, but any spelling works for me.  implements strikes me as
an elegant counterpart to interface and risks minimal breakage.  Can we
still import and say implements() for b/w compatibility and for those of us
who do want an explicit statement like that?
If I understand Guido's proposal correctly, it should be possible to make a 
backward-compatible 'implements()' declaration function.  Maybe not *easy*, 
but certainly possible.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Thomas Heller
Alex Martelli [EMAIL PROTECTED] writes:

 PEP: 246
 Title: Object Adaptation

Minor nit (or not?): You could provide a pointer to the Liskov
substitution principle, for those reader that aren't too familiar with
that term.

Besides, the text mentions three times that LiskovViolation is a
subclass of AdaptionError (plus once in the ref impl section).

Thomas

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Bob Ippolito
On Jan 10, 2005, at 16:38, Phillip J. Eby wrote:
At 07:42 PM 1/10/05 +0100, Alex Martelli wrote:
On 2005 Jan 10, at 18:43, Phillip J. Eby wrote:
   ...
I am not saying we shouldn't have a tp_conform; just suggesting that 
it may be appropriate for functions and modules (as well as classic 
classes) to have their tp_conform delegate back to 
self.__dict__['__conform__'] instead of a null implementation.
I have not considered conformance of such objects as functions or 
modules; if that is important,
It's used in at least Zope and PEAK; I don't know if it's in use in 
Twisted.
SVN trunk of Twisted (what will be 2.0) uses zope.interface.  It still 
has the older stuff implemented as a wrapper on top of zope.interface, 
but I think the guideline is to just use zope.interface directly for 
new code dependent on Twisted 2.0.

-bob
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-10 Thread Phillip J. Eby
At 05:42 PM 1/10/05 -0500, Bob Ippolito wrote:
On Jan 10, 2005, at 16:38, Phillip J. Eby wrote:
At 07:42 PM 1/10/05 +0100, Alex Martelli wrote:
On 2005 Jan 10, at 18:43, Phillip J. Eby wrote:
   ...
I am not saying we shouldn't have a tp_conform; just suggesting that it 
may be appropriate for functions and modules (as well as classic 
classes) to have their tp_conform delegate back to 
self.__dict__['__conform__'] instead of a null implementation.
I have not considered conformance of such objects as functions or 
modules; if that is important,
It's used in at least Zope and PEAK; I don't know if it's in use in Twisted.
SVN trunk of Twisted (what will be 2.0) uses zope.interface.
What I meant was, I don't know if Twisted actually *uses* interface 
declarations for modules and functions.  It has the ability to do so, 
certainly.  I was just saying I didn't know if the ability is actually used.

PEAK uses some interfaces for functions, but I don't think I've ever used 
them for modules, and can think of only one place in PEAK where it would 
make sense to declare a module as supporting an interface.  Zope policy is 
to use interfaces for *everything*, though, including documenting the 
interface provided by modules.

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com