Re: [Python-Dev] Son of PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 12:01 AM 1/13/05 -0500, Michael Walter wrote:
What am I missing?
The fact that this is a type-declaration issue, and has nothing to do with 
*how* types are checked.

Note that I'm only proposing:
1) a possible replacement for PEP 246 that leaves 'adapt()' as a function, 
but uses a different internal implementation,

2) a very specific notion of what an operation is, that doesn't require an 
interface to exist if there is already some concrete type that the 
interface would be an abstraction of,

3) a strawman syntax for declaring the relationship between operations
In other words, compared to the previous state of things, this should 
actually require *fewer* interfaces to accomplish the same use cases, and 
it doesn't require Python to have a built-in notion of "interface", because 
the primitive notion is an operation, not an interface.

Oh, and I think I've now figured out how to define a type-safe version of 
Ping's "abstract operations" concept that can play in the 
non-generic-function implementation, but I really need some sleep, so I 
might be hallucinating the solution.  :)

Anyway, so far it seems like it can all be done with a handful of decorators:
@implements(base_operation, for_type=None)
  (for_type is the "adapt *from*" type, defaulting to the enclosing class 
if used inside a class body)

@override
  (means the method is overriding the one in a base class, keeping the 
same operation correspondence(s) defined for the method in the base class)

@abstract(base_operation, *required_operations)
  (indicates that this implementation of base_operation requires the 
ability to use the specified required_operations on a target instance.  The 
adapter machinery can then "safely fail" if the operations aren't 
available, or if it detects a cycle between mutually-recursive abstract 
operations that don't have a non-abstract implementation.  An abstract 
method can be used to perform the operation on any object that provides the 
required operations, however.)

Anyway, from the information provided by these decorators, you can generate 
adapter classes for any operation-based interfaces.  I don't have a planned 
syntax or API for defining attribute correspondences as yet, but it should 
be possible to treat them internally as a get/set/del operation triplet, 
and then just wrap them in a descriptor on the adapter class.

By the way, saying "generate" makes it sound more complex than it is: just 
a subclass of 'object' with a single slot that points to the wrapped source 
object, and contains simple descriptors for each available operation of the 
"protocol" type that call the method implementations, passing in the 
wrapped object.  So really "generate" means, "populate a dictionary with 
descriptors and then call 'type(name,(object,),theDict)'".

A side effect of this approach, by the way, is that since adapters are 
*never* composed (transitively or otherwise), we can *always* get back to 
the "original" object.  So, in theory we could actually have 
'adapt(x,object)' always convert back to the original unwrapped object, if 
we needed it.  Likewise, adapting an already-adapted object can be safe 
because the adapter machinery knows when it's dealing with one of its own 
adapters, and unwrap it before rewrapping it with a new adapter.

Oh, btw, it should at least produce a warning to declare multiple 
implementations for the same operation and source type, if not an outright 
error.  Since there's no implicit transitivity in this system (either 
there's a registered implementation for something or there isn't), there's 
no other form of ambiguity besides dual declarations of a point-to-point 
adaptation.

Hm.  You know, this also solves the interface inheritance problem; under 
this scheme, if you inherit an operation from a base interface, it doesn't 
mean that you provide the base interface.

Oh, actually, you can still also do interface adaptation in a somewhat more 
restrictive form; you can declare abstract operations for the target 
interface in terms of operations in the base interface.  But it's much more 
controlled because you never stack adapters on adapters, and the system can 
tell at adaptation time what operations are and aren't actually available.

Even more interesting: Alex's "loss of middle name" example can't be 
recreated in this system as a problem, at least if I'm still thinking 
clearly.  But I'm probably not, so I'm going to bed now.  :)

___
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] Son of PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 09:57 PM 1/12/05 -0500, Phillip J. Eby wrote:
class StringIO:
def read(self, bytes) implements file.read:
# etc...
could be used to indicate the simple case where you are conforming to an 
existing operation definition.  A third-party definition, of the same 
thing might look like this:

def file.read(self: StringIO, bytes):
return self.read(bytes)
Assuming, of course, that that's the syntax for adding an implementation 
to an existing operation.
After some more thought, I think this approach:
1. Might not actually need generic functions to be implemented.  I need to 
think some more about properties and Ka-Ping Yee's abstract method idea, to 
make sure they can be made to work without "real" generic functions, but a 
basic version of this approach should be implementable with just a handful 
of dictionaries and decorators.

2. Can be prototyped in today's Python, whether generic functions are used 
or not (but the decorator syntax might be ugly, and the decorator 
implementations might be hacky)

3. May still have some rough bits with respect to subclassing & Liskov; I 
need to work through that part some more.  My preliminary impression is 
that it might be safe to consider inherited (but not overridden) methods as 
being the same logical operation.  That imposes some burden on subclassers 
to redeclare compatibility on overridden methods, but OTOH would be 
typesafe by default.

4. Might be somewhat more tedious to declare adaptations with, than it 
currently is with tools like PyProtocols.

Anyway, the non-generic-function implementation would be to have 'adapt()' 
generate (and cache!) an adapter class by going through all the methods of 
the target class and then looking them up in its 'implements' registry, 
while walking up the source class' __mro__ to find the most-specific 
implementation for that type (while checking for 
overridden-but-not-declared methods along the way).  There would be no 
__conform__ or __adapt__ hooks needed.

Interestingly, C# requires you to declare when you are intentionally 
overriding a base class method, in order to avoid accidentally overriding a 
new method added to a base class later.  This concept actually contains a 
germ of the same idea, requiring overrides to specify that they still 
conform to the base class' operations.

Maybe this weekend I'll be able to spend some time on whipping up some sort 
of prototype, and hopefully that will answer some of my open 
questions.  It'll also be interesting to see if I can actually use the 
technique directly on existing interfaces and adaptation, i.e. get some 
degree of PyProtocols backward-compatibility.  It might also be possible to 
get backward-compatibility for Zope too.  In each case, the backward 
compatibility mechanism would be to change the adapter/interface 
declaration APIs to be equivalent to assertions about all the operations 
defined in a particular interface, against the concrete class you're 
claiming implements the interface.

However, for both PEAK and Zope, it would likely be desirable to migrate 
any interfaces like "mapping object" to be based off of operations in e.g. 
the 'dict' type rather than rolling their own IReadMapping and such.

___
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] Son of PEP 246, redux

2005-01-12 Thread Michael Walter
> instead interfaces can be defined in terms of individual operations, and 
> those operations can be initially defined by an abstract base, concrete 
> class, or an "interface" object.
I think this is quite problematic in the sense that it will force many
dummy interfaces to be created. At least without type inference, this
is a no-no.

Consider: In order to type a function like:

def f(x):
  # ...
  x.foo()
  # ...

...so that type violations can be detected before the real action
takes place, you would need to create a dummy interface as in:

interface XAsFUsesIt:
  def foo():
pass

def f(x : XAsFUsesIt):
  # ...

...or you would want type inference (which at compile time types x as
"a thing which has a 'nullary' foo() function) and a type system like
System CT.

Former appears cumbersome (as it should really be done for every
function), latter too NIMPY-ish . What am I missing?

Sleepingly yours,
Michael


On Wed, 12 Jan 2005 23:48:47 -0500, Phillip J. Eby
<[EMAIL PROTECTED]> wrote:
> At 11:26 PM 1/12/05 -0500, Clark C. Evans wrote:
> >Regardless,
> >getting back to the main goal I had when writing PEP 246 -- your
> >alternative proposal still doesn't seem to provide a mechanism for
> >component developers to have a dialogue with one another to connect
> >components without involving the application programmer.
> 
> Eh?  You still have adapt(); you still have adapters.  The only difference
> is that I've specified a way to not need "interfaces" - instead interfaces
> can be defined in terms of individual operations, and those operations can
> be initially defined by an abstract base, concrete class, or an "interface"
> object.  Oh, and you don't have to write adapter *classes* - you write
> adapting *methods* for individual operations.  This can be done by the
> original author of a class or by a third party -- just like with PEP 246.
> 
> ___
> 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/michael.walter%40gmail.com
>
___
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] Son of PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 11:26 PM 1/12/05 -0500, Clark C. Evans wrote:
Regardless,
getting back to the main goal I had when writing PEP 246 -- your
alternative proposal still doesn't seem to provide a mechanism for
component developers to have a dialogue with one another to connect
components without involving the application programmer.
Eh?  You still have adapt(); you still have adapters.  The only difference 
is that I've specified a way to not need "interfaces" - instead interfaces 
can be defined in terms of individual operations, and those operations can 
be initially defined by an abstract base, concrete class, or an "interface" 
object.  Oh, and you don't have to write adapter *classes* - you write 
adapting *methods* for individual operations.  This can be done by the 
original author of a class or by a third party -- just like with PEP 246.

___
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] Son of PEP 246, redux

2005-01-12 Thread Clark C. Evans
Phillip,

In my mind, the driving use-case for PEP 246 was to allow causual
programmers to plug components together and have it 'just work'; it
does this by enabling the component vendors to carry on a discussion
via __adapt__ and __conform__ to work together.  I was not picturing
that your average developer would be using this sort of thing.

On Wed, Jan 12, 2005 at 09:57:07PM -0500, Phillip J. Eby wrote:
| First, adapter abuse is *extremely* attractive to someone new to the 
| concept -- so from here on out I'm going to forget about the idea that we 
| can teach people to avoid this solely by telling them "the right way to 
| do it" up front.
| 
| The second, much subtler point I noticed from your posts, was that 
| *adapter abuse tends to sooner or later result in adapter diamonds*.

However, I'd like to assert that these cases emerge when you have a
registry /w automatic transitive adaptation.  These problems can be
avoided quite easily by:

   - not doing transitive adaptation automatically

   - making it an error to register more than one adapter from 
 A to Z at any given time; in effect, ban diamonds from ever
 being created

   - make it easy for a user to construct and register an adapter
 from A to Z, via an intermediate X,

adapt.registerTransitive(A,X,Z)
 
   - if an adaptation from A to Z isn't possible, give a very
 meaningful error listing the possible pathways that one
 could build a 'transitive adaption', adaptation path', 
 perhaps even showing the command that will do it:

 adapt.registerTransitive(A,B,C,Z)
 adapt.registerTranstive(A,Q,Z)
 adapt.registerTranstive(A,X,Z)

The results of this operation:

   - most component vendors will use __adapt__ and __conform__
 rather than use the 'higher-precedent' registry; therefore,
 transitive adaption isn't that common to start with

   - if two libraries register incompatible adpater chains
 during the 'import' of the module, then it will be an
 error that the casual developer will associate with 
 the module, and not with their code
 
   - casual users are given a nice message, like

  "Cannot automatically convert a String to a File. 
 
   Perhaps you should do a manual conversion of your String
   to a File.  Alternatively, there happen to be two adaptation
   paths which could do this for you, but you have to explicitly
   enable the pathway which matches your intent:
   
   To convert a String to a File via StringIO, call:
   adapt.registerTranstive(String,StringIO,File)

   To convert a String to a File via FileName, call:
   adapt.registerTranstive(String,FileName,File)"

| What that suggests to me is that it might well be safe enough in practice 
| to let new users of adaptation whack their hand with the mallet now and 
| then, given that *now* it's possible to give a much better explanation of 
| "as a" than it was before.

By disabling (the quite dangerous?) transitive adaptation, one could
guide the user along to the result they require without having them
shoot themselves in the foot first.

| What this also suggests to me is that maybe adaptation and interfaces are 
| the wrong solution to the problems we've been trying to solve with them 
| -- adding more objects to solve the problems created by having lots of 
| objects.  :)

I didn't see how your remaining post, in particular, Dylan's protocol was 
much different from an mixin/abstract-base-class. Regardless,
getting back to the main goal I had when writing PEP 246 -- your
alternative proposal still doesn't seem to provide a mechanism for
component developers to have a dialogue with one another to connect
components without involving the application programmer. 

Cheers!

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 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] Re: [Csv] csv module and universal newlines

2005-01-12 Thread Andrew McNamara
>Isn't universal newlines only used for reading?

That right. And the CSV reader has it's own version of univeral newlines
anyway (from the py1.5 days).

>I have had no problems using the csv module for reading files with 
>universal newlines by opening the file myself or providing an iterator.

Neither have I, funnily enough.

>Unicode, on the other hand, I have had problems with.

Ah, so somebody does want it then? Good to hear. Hard to get motivated
to make radical changes without feedback.

-- 
Andrew McNamara, Senior Developer, Object Craft
http://www.object-craft.com.au/
___
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] Son of PEP 246, redux

2005-01-12 Thread Phillip J. Eby
This is a pretty long post; it starts out as discussion of educational 
issues highlighted by Clark and Ian, but then it takes the motivation for 
PEP 246 in an entirely new direction -- possibly one that could be more 
intuitive than interfaces and adapters as they are currently viewed in 
Zope/Twisted/PEAK etc., and maybe one that could be a much better fit with 
Guido's type declaration ideas.  OTOH, everybody may hate the idea and 
think it's stupid, or if they like it, then Alex may want to strangle me 
for allowing doubt about PEP 246 to re-enter Guido's head.  Either way, 
somebody's going to be unhappy. 

At 05:54 PM 1/12/05 -0500, Clark C. Evans wrote:
   String -> PathName -> File
   String -> StringIO -> File
Okay, after reading yours and Ian's posts and thinking about them some 
more, I've learned some really interesting things.

First, adapter abuse is *extremely* attractive to someone new to the 
concept -- so from here on out I'm going to forget about the idea that we 
can teach people to avoid this solely by telling them "the right way to do 
it" up front.

The second, much subtler point I noticed from your posts, was that *adapter 
abuse tends to sooner or later result in adapter diamonds*.

And that is particularly interesting because the way that I learned how NOT 
to abuse adapters, was by getting slapped upside the head by PyProtocols 
pointing out when adapter diamonds had resulted!

Now, that's not because I'm a genius who put the error in because I 
realized that adapter abuse causes diamonds.  I didn't really understand 
adapter abuse until *after* I got enough errors to be able to have a good 
intuition about what "as a" really means.

Now, I'm not claiming that adapter abuse inevitably results in a detectable 
ambiguity, and certainly not that it does so instantaneously.  I'm also not 
claiming that some ambiguities reported by PyProtocols might not be 
perfectly harmless.  So, adaptation ambiguity is a lot like a PyChecker 
warning: it might be a horrible problem, or it might be that you are just 
doing something a little unusual.

But the thing I find interesting is that, even with just the diamonds I 
ended up creating on my own, I was able to infer an intuitive concept of 
"as a", even though I hadn't fully verbalized the concepts prior to this 
lengthy debate with Alex forcing me to single-step through my thought 
processes.

What that suggests to me is that it might well be safe enough in practice 
to let new users of adaptation whack their hand with the mallet now and 
then, given that *now* it's possible to give a much better explanation of 
"as a" than it was before.

Also, consider this...  The larger an adapter network there is, the 
*greater* the probability that adapter abuse will create an ambiguity -- 
which could mean faster learning.

If the ambiguity error is easily looked up in documentation that explains 
the as-a concept and the intended working of adaptation, so much the 
better.  But in the worst case of a false alarm (the ambiguity was 
harmless), you just resolve the ambiguity and move on.


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?
The *real* problem here isn't the ambiguity, it's that Pathname->File is 
"adapter abuse".  However, the fact that it results in an ambiguity is a 
useful clue to fixing the problem.  Each time I sat down with one of these 
detected ambiguities, I learned better how to define sensible interfaces 
and meaningful adaptation.  I would not have learned these things by simply 
not having transitive adaptation.


| 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.
The next thing that I realized from your posts is that there's another 
education issue for people who haven't used adaptation, and that's just how 
precisely interfaces need to b

Re: [Python-Dev] Re: [Csv] csv module and universal newlines

2005-01-12 Thread Bob Ippolito
On Jan 12, 2005, at 21:39, Skip Montanaro wrote:
Jack> On MacOSX you really want universal newlines. CSV files 
produced
Jack> by older software (such as AppleWorks) will have \r line
Jack> terminators, but lots of other programs will have files with
Jack> normal \n terminators.

Won't work.  You have to be able to write a Windows csv file on any
platform.  Binary mode is the only way to get that.
Isn't universal newlines only used for reading?
I have had no problems using the csv module for reading files with 
universal newlines by opening the file myself or providing an iterator.

Unicode, on the other hand, I have had problems with.
-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] Re: [Csv] csv module and universal newlines

2005-01-12 Thread Skip Montanaro
Jack> On MacOSX you really want universal newlines. CSV files produced
Jack> by older software (such as AppleWorks) will have \r line
Jack> terminators, but lots of other programs will have files with
Jack> normal \n terminators.

Won't work.  You have to be able to write a Windows csv file on any
platform.  Binary mode is the only way to get that.

Skip

___
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] Re: [Csv] csv module and universal newlines

2005-01-12 Thread Skip Montanaro

>> The idea of the check is to enforce binary mode on those objects that
>> support a mode if the desired line terminator doesn't match the
>> platform's line terminator.

Andrew> Where that falls down, I think, is where you want to read an
Andrew> alien file - in fact, under unix, most of the CSV files I read
Andrew> use \r\n for end-of-line.

Well, you can either require 'b' in that situation or "know" that 'b' isn't
needed on Unix systems.

Andrew> Also, I *really* don't like the idea of looking for a mode
Andrew> attribute on the supplied iterator - it feels like a layering
Andrew> violation. We've advertised the fact that it's an iterator, so
Andrew> we shouldn't be using anything but the iterator protocol.

The fundamental problem is that the iterator protocol on files is designed
for use only with text mode (or universal newline mode, but that's just as
much of a problem in this context).  I think you either have to abandon the
iterator protocol or peek under the iterator's covers to make sure it reads
and writes in binary mode.  Right now, people on windows create writers like
this

writer = csv.writer(open("somefile", "w"))

and are confused when their csv files contain blank lines.  I think the
reader and writer objects have to at least emit a warning when they discover
a source or destination that violates the requirements.

Skip
___
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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Phillip J. Eby
At 02:03 PM 1/12/05 -0600, Skip Montanaro wrote:
I don't think that's appropriate in this case.  Liskov violation is
something precise.  I don't think that changing what you call it will help
beginners understand it any better in this case.  I say leave it as it and
make sure it's properly documented.
Actually, the whole discussion is kind of backwards; you should never *get* 
a Liskov violation error, because it's raised strictly for control flow 
inside of __conform__ and caught by adapt().  So the *only* way you can see 
this error is if you call __conform__ directly, and somebody added code 
like this:

raise LiskovViolation
So, it's not something you need to worry about a newbie seeing.  The *real* 
problem with the name is knowing that you need to use it in the first place!

IMO, it's simpler to handle this use case by letting __conform__ return 
None, since this allows people to follow the One Obvious Way to not conform 
to a particular protocol.

Then, there isn't a need to even worry about the exception name in the 
first place, either...

___
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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Phillip J. Eby
At 05:54 PM 1/12/05 -0700, Steven Bethard wrote:
Not that my opinion counts for much =), but returning None does seem
much simpler to me.  I also haven't seen any arguments against this
route of handling protocol nonconformance...  Is there a particular
advantage to the exception-raising scheme?
Only if there's any objection to giving the 'object' type a default 
__conform__ method that returns 'self' if 'isinstance(protocol,ClassTypes) 
and isinstance(self,protocol)'.

___
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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Steven Bethard
On Wed, 12 Jan 2005 19:49:06 -0500, Phillip J. Eby
<[EMAIL PROTECTED]> wrote:
> So the *only* way you can see
> this error is if you call __conform__ directly, and somebody added code
> like this:
> 
>  raise LiskovViolation
> 
> So, it's not something you need to worry about a newbie seeing.  The *real*
> problem with the name is knowing that you need to use it in the first place!
> 
> IMO, it's simpler to handle this use case by letting __conform__ return
> None, since this allows people to follow the One Obvious Way to not conform
> to a particular protocol.

Not that my opinion counts for much =), but returning None does seem
much simpler to me.  I also haven't seen any arguments against this
route of handling protocol nonconformance...  Is there a particular
advantage to the exception-raising scheme?

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] Re: [Csv] csv module and universal newlines

2005-01-12 Thread Jack Jansen
On 12-jan-05, at 2:59, Skip Montanaro wrote:
terminators = {"darwin": "\r",
   "win32": "\r\n"}
if (dialect.lineterminator != terminators.get(sys.platform, "\n") 
and
   "b" not in getattr(f, "mode", "b")):
   raise IOError, ("%s not opened in binary mode" %
   getattr(f, "name", "???"))
On MacOSX you really want universal newlines. CSV files produced by 
older software (such as AppleWorks) will have \r line terminators, but 
lots of other programs will have files with normal \n terminators.
--
Jack Jansen, <[EMAIL PROTECTED]>, http://www.cwi.nl/~jack
If I can't dance I don't want to be part of your revolution -- Emma 
Goldman

___
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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Fredrik Lundh
Just van Rossum wrote:

> ...and then there are those Python users who have no formal CS
> background at all. Python is used quite a bit by people who's main job
> is not programming.

...and among us who do programming as a main job, I can assure that I'm
not the only one who, if told by a computer that something I did was a LSP
violation, would take that computer out in the backyard and shoot it.  or at
least hit it with a shovel, or something.

 



___
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
[Clark]
>   - add a flag to adapt, allowTransitive, which defaults to False

That wouldn't work very well when most adapt() calls are invoked
implicitly through signature declarations (per my blog's proposal).

-- 
--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



[Python-Dev] Re: Recent IBM Patent releases

2005-01-12 Thread Terry Reedy

"Scott David Daniels" <[EMAIL PROTECTED]>
> IBM has recently released 500 patents for use in opensource code.
>
> http://www.ibm.com/ibm/licensing/patents/pledgedpatents.pdf
>
> "...In order to foster innovation and avoid the possibility that a
> party will take advantage of this pledge and then assert patents or
> other intellectual property rights of its own against Open Source
> Software, thereby limiting the freedom of IBM or any other Open
> Source developer to create innovative software programs, the
> commitment not to assert any of these 500 U.S. patents and all
> counterparts of these patents issued in other countries is
> irrevocable except that IBM reserves the right to terminate this
> patent pledge and commitment only with regard to any party who files
> a lawsuit asserting patents or other intellectual property rights
> against Open Source Software."

The exception is, of course, aimed for now at SCO and their ridiculous 
lawsuit against Linux and IBM with respect to Linux.

from another post
> I believe our current policy is that the author warrants that the code
> is his/her own work and not encumbered by any patent.

Without a qualifier such as 'To the best of my knowledge', the latter is an 
impossible warrant both practically, for an individual author without 
$1000s to spend on a patent search, and legally.  Legally, there is no 
answer until the statute of limitations runs out or until there is an 
after-the-fact final answer provided by the court system.

Terry J. Reedy



___
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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread stelios xanthakis
Skip Montanaro wrote:
   Michael> Guido writes:
   >> How about SubstitutabilityError?
I don't think that's any better.  At the very least, people can Google for
"Liskov violation" to educate themselves.  I'm not sure that the results of
a Google search for "Subtitutability Error" will be any clearer
...
I don't think that's appropriate in this case.  Liskov violation is
something precise.  I don't think that changing what you call it will help
beginners understand it any better in this case.  I say leave it as it and
make sure it's properly documented.
 

Yes but in order to fall into a Liskov Violation, one will have to use 
extreme OOP features (as I understand from the ongoing
discussion for which, honestly, I understand nothing:). So it's not like 
it will happen often and when it happens
it will make sense to the architects who made such complex things.

+1 on SubstitutabilityError or something easier and moreover because of 
the fact that some people
really don't care who Liskov is and what he/she discovered, and whether 
that same thing would had
been discovered anyway 2 mothns later by somebody else if the Liskov 
person wasn't there.

St.
___
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 Phillip J. Eby
At 03:19 PM 1/12/05 -0700, Steven Bethard wrote:
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 the former, but not the latter.  A string certainly can act-as-a path 
object; there are numerous stdlib functions that take a string and then use 
it "as a" path object.  In principle, a future version of Python might take 
path objects for these operations, and automatically adapt strings to them.

But a path can't act as a file; that indeed makes no sense.
___
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] Re: [Csv] csv module and universal newlines

2005-01-12 Thread Andrew McNamara
>You can argue that reading csv data from/writing csv data to a file on
>Windows if the file isn't opened in binary mode is an error.  Perhaps we
>should enforce that in situations where it matters.  Would this be a start?
>
>terminators = {"darwin": "\r",
>   "win32": "\r\n"}
>
>if (dialect.lineterminator != terminators.get(sys.platform, "\n") and
>   "b" not in getattr(f, "mode", "b")):
>   raise IOError, ("%s not opened in binary mode" %
>   getattr(f, "name", "???"))
>
>The elements of the postulated terminators dictionary may already exist
>somewhere within the sys or os modules (if not, perhaps they should be
>added).  The idea of the check is to enforce binary mode on those objects
>that support a mode if the desired line terminator doesn't match the
>platform's line terminator.

Where that falls down, I think, is where you want to read an alien
file - in fact, under unix, most of the CSV files I read use \r\n for
end-of-line.

Also, I *really* don't like the idea of looking for a mode attribute
on the supplied iterator - it feels like a layering violation. We've
advertised the fact that it's an iterator, so we shouldn't be using
anything but the iterator protocol.

-- 
Andrew McNamara, Senior Developer, Object Craft
http://www.object-craft.com.au/
___
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 Carlos Ribeiro
On Wed, 12 Jan 2005 16:07:37 -0600, Ian Bicking <[EMAIL PROTECTED]> wrote:
> 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.

To put it quite bluntly: many people never bother to implement the
_full_ interface of something if all they need is a half baked
implementation. For example, I may get away with a sequence-like
object in many situations without slice suport in getitem, or a dict
with some of the iteration methods. Call it lazyness, but this is
known to happen quite often, and Python is quite forgiving in this
respect. Add the global scope of the adapter registry & transitivity
to this and things may become much harder to debug...

...but on the other hand, transitivity is a powerful tool in the hands
of an expert programmer, and allows to write much shorter & cleaner
code. Some balance is needed.

-- 
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 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 Ian Bicking
Phillip J. Eby wrote:
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.
I haven't read through the entire thread yet, so forgive me if I'm 
redundant.

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.  It's also quite 
unambiguous that a string could be adapted to a StringIO object, though 
I'm not sure it's reasonable.  In fact, it seems like an annoying but 
entirely possible case that some library would register such an adapter, 
and mess things up globally for everyone who didn't want such an 
adaptation to occur!  But that's an aside.  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).

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.  Or if I wanted it to take strings (that represented 
content) or file-like objects, I'd adapt to a file object and if that 
failed I'd adapt to a string, then convert to a StringIO object.  A 
two-step adaptation encodes specific intention that it seems transitive 
adaption would be blind to.

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.

--
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-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 a

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 
ha

Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Phillip J. Eby
At 08:59 PM 1/12/05 +0100, Alex Martelli wrote:
Even though Guido claimed I have been belaboring the following point, I do 
think it's crucial and I still haven't seen you answer it.
My post on that probably crossed with this post of yours; it contains an 
excruciating analysis of why I chose to consider such paths 
dubious.  However, I'll briefly answer your specific questions 
here.  (Well, briefly for ME! ;) )


  If *any* I1->I2 adapter, by the very fact of its existence, asserts 
it's the *absolute best way* to adapt ANY implementation of I1 into I2; 
then why should the existence of two equal-length shortest paths 
A->I1->I2 and A->I3->I2 be considered a problem in any sense?  Pick 
either, at random or by whatever rule: you trust that they're BOTH the 
absolute best, so they must be absolutely identical anyway.
Because if you have asserted that it is the absolute best, why did you 
write *another* one that's equally good?  This suggests that at least one 
of the paths you ended up with was unintentional: created, for example, via 
inappropriate use of interface inheritance.

Anyway, the other post has a detailed analysis for all the circumstances I 
can think of where you *might* have such a set of ambiguous adapter paths, 
and why it's excruciatingly rare that you would not in fact care when such 
a situation existed, and why the error is therefore valuable in pointing 
out the (almost certainly unintended) duplication.


If you agree that this is the only sensible behavior, and PyProtocols' 
current behavior (TypeError for two paths of equal length save in a few 
special cases), then I guess can accept your stance that providing 
adaptation between interfaces implies the strongest possible degree of 
commitment to perfection, and that this new conception of *absolute best 
way* entirely and totally replaces previous weaker and more sensible 
descriptions, such as for example in 
 that 
shorter chains "are less likely to be a ``lossy'' conversion".
``less likely'' and ``absolute best way'' just can't coexist.  Two 
"absolute best ways" to do the same thing are exactly equally likely to be 
``lossy'': that likelihood is ZERO, if "absolute" means anything.
First off, as a result of our conversations here, I'm aware that the 
PyProtocols documentation needs updating; it was based on some of my 
*earliest* thinking about adaptation, before I realized how critical the 
distinction between class-to-interface and interface-to-interface 
adaptation really was.  And, my later thinking has only really been 
properly explained (even to my satisfaction!) during this 
discussion.  Indeed, there are lots of things I know now about when to 
adapt and when not to, that I had only the faintest idea of when I 
originally wrote the documentation.

Second, if the error PyProtocols produces became a problem in practice, it 
could potentially be downgraded to a warning, or even disabled 
entirely.  However, my experience with it has been that the *real* reason 
to flag adapter ambiguities is that they usually reveal some *other* 
problem, that would be much harder to find otherwise.


((Preferring shorter chains as a heuristic for faster ones may be very 
reasonable approach if performance is a secondary consideration, as I've 
already mentioned; if performance were more important than that, then 
other ``costs'' besides the extreme NO_ADAPTER_NEEDED [[0 cost]] and 
DOES_NOT_SUPPORT [[infinite cost]] should be accepted, and the 
minimal-cost path ensured -- I do not think any such complication is 
warranted)).
Actually, the nature of the transitive algorithm PyProtocols uses is that 
it must track these running costs and pass them around anyway, so it is 
always possible to call one of its primitive APIs to force a certain cost 
consideration.  However, I have never actually had to use it, and I 
discourage others from playing with it, because I think the need to use it 
would be highly indicative of some other problem, like inappropriate use of 
adaptation or at least of I-to-I relationships.


If you agree that it cannot be an error to have two separate paths of 
"absolute best ways" (thus equally perfect) of equal length, then I can 
accept your stance that one must ensure the "absolute best way" each time 
one codes and registers an I -> I adapter (and each time one interface 
inherits another interface, apparently); I can then do half the rewrite of 
the PEP 246 draft (the changes already mentioned and roughly agreed) and 
turn it over to you as new first author to complete with the transitivity 
details &c.

If there is any doubt whatsoever marring that perfection, that "absolute 
best way", then I fear we're back at square one.
The only doubt is that somebody may have *erroneously* created a duplicate 
adapter, or an unintended duplicate path via a NO_ADAPTER_NEEDED link (e.g. 
by declaring that a class implements an interface directly, or interfa

RE: [Python-Dev] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Just van Rossum
Skip Montanaro wrote:

> 
> Michael> This must be one of those cases where I am mislead by my
> Michael> background...  I thought of Liskov substitution principle 
> Michael> as a piece of basic CS background that everyone learned 
> Michael> in school (or from the net, or wherever they learned
> Michael> programming). Clearly, that's not true.
> 
> Note that some us were long out of school by the time Barbara Liskov
> first published the idea (in 1988 according to
> http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple).  Also, since it
> pertains to OO programming it was probably not taught widely until
> the mid-90s.  That means a fair number of people will have never
> heard about it.

...and then there are those Python users who have no formal CS
background at all. Python is used quite a bit by people who's main job
is not programming.

I'm one of those, and whatever I know about CS, I owe it mostly
to the Python community. I learned an awful lot just by hanging out on
various Python mailing lists.

> Michael> Guido writes:
> >> How about SubstitutabilityError?
> 
> I don't think that's any better.  At the very least, people can
> Google for "Liskov violation" to educate themselves.  I'm not sure
> that the results of a Google search for "Subtitutability Error" will
> be any clearer.

Well, with a bit of luck Google will point to the Python documentation
then...

Just
___
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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Kurt B. Kaiser
Skip Montanaro <[EMAIL PROTECTED]> writes:

> I don't think that's appropriate in this case.  Liskov violation is
> something precise.  I don't think that changing what you call it will help
> beginners understand it any better in this case.  I say leave it as it and
> make sure it's properly documented.

+1
-- 
KBK
___
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 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 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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Skip Montanaro

Michael> This must be one of those cases where I am mislead by my
Michael> background...  I thought of Liskov substitution principle as a
Michael> piece of basic CS background that everyone learned in school
Michael> (or from the net, or wherever they learned
Michael> programming). Clearly, that's not true.

Note that some us were long out of school by the time Barbara Liskov first
published the idea (in 1988 according to
http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple).  Also, since it
pertains to OO programming it was probably not taught widely until the
mid-90s.  That means a fair number of people will have never heard about it.

Michael> Guido writes:
>> How about SubstitutabilityError?

I don't think that's any better.  At the very least, people can Google for
"Liskov violation" to educate themselves.  I'm not sure that the results of
a Google search for "Subtitutability Error" will be any clearer.

Michael> It would be less precise and informative to ME but apparently
Michael> more so to a beginner. Obviously, we should support the
Michael> beginner!

I don't think that's appropriate in this case.  Liskov violation is
something precise.  I don't think that changing what you call it will help
beginners understand it any better in this case.  I say leave it as it and
make sure it's properly documented.

Skip

___
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:06, Phillip J. Eby wrote:
At 10:16 AM 1/12/05 -0800, Guido van Rossum wrote:
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.
Another possibility; I've realized from Alex's last mail that there's 
a piece of my reasoning that I haven't been including, and now I can 
actually explain it clearly (I hope).  In my view, there are at least 
two kinds of adapters, with different fidelity 
requirements/difficulty:

   class -> interface  ("lo-fi" is okay)
   interface -> interface  (It better be perfect!)
If you cannot guarantee that your interface-to-interface adapter is 
the absolute best way to adapt *any* implementation of the source 
interface, you should *not* treat it as an interface-to-interface 
adapter, but rather as a class-to-interface adapter for the specific 
classes that need it.  And, if transitivity exists, it is now 
restricted to a sensible subset of the possible paths.
Even though Guido claimed I have been belaboring the following point, I 
do think it's crucial and I still haven't seen you answer it.  If *any* 
I1->I2 adapter, by the very fact of its existence, asserts it's the 
*absolute best way* to adapt ANY implementation of I1 into I2; then why 
should the existence of two equal-length shortest paths A->I1->I2 and 
A->I3->I2 be considered a problem in any sense?  Pick either, at random 
or by whatever rule: you trust that they're BOTH the absolute best, so 
they must be absolutely identical anyway.

If you agree that this is the only sensible behavior, and PyProtocols' 
current behavior (TypeError for two paths of equal length save in a few 
special cases), then I guess can accept your stance that providing 
adaptation between interfaces implies the strongest possible degree of 
commitment to perfection, and that this new conception of *absolute 
best way* entirely and totally replaces previous weaker and more 
sensible descriptions, such as for example in 
 
that shorter chains "are less likely to be a ``lossy'' conversion".  
``less likely'' and ``absolute best way'' just can't coexist.  Two 
"absolute best ways" to do the same thing are exactly equally likely to 
be ``lossy'': that likelihood is ZERO, if "absolute" means anything.
((Preferring shorter chains as a heuristic for faster ones may be very 
reasonable approach if performance is a secondary consideration, as 
I've already mentioned; if performance were more important than that, 
then other ``costs'' besides the extreme NO_ADAPTER_NEEDED [[0 cost]] 
and DOES_NOT_SUPPORT [[infinite cost]] should be accepted, and the 
minimal-cost path ensured -- I do not think any such complication is 
warranted)).

I think maybe this gets us a little bit closer to having a unified (or 
at least unifiable) view on the problem area.  If Alex agrees that 
class-to-interface adaptation is an acceptable solution for limiting 
the transitivity of noisy adaptation while still allowing some degree 
of implicitness, then maybe we have a winner.
If you agree that it cannot be an error to have two separate paths of 
"absolute best ways" (thus equally perfect) of equal length, then I can 
accept your stance that one must ensure the "absolute best way" each 
time one codes and registers an I -> I adapter (and each time one 
interface inherits another interface, apparently); I can then do half 
the rewrite of the PEP 246 draft (the changes already mentioned and 
roughly agreed) and turn it over to you as new first author to complete 
with the transitivity details &c.

If there is any doubt whatsoever marring that perfection, that 
"absolute best way", then I fear we're back at square one.

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 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 03:48 PM 1/12/05 +0100, Alex Martelli wrote:
Demanding that the set of paths of minimal available length has exactly 
one element is strange, though, IF one is assuming that all adaptation 
paths are exactly equivalent except at most for secondary issues of 
performance (which are only adjudicated by the simplest heuristic: if 
those issues were NOT considered minor/secondary, then a more 
sophisticated scheme would be warranted, e.g. by letting the programmer 
associate a cost to each step, picking the lowest-cost path, AND letting 
the caller of adapt() also specify the maximal acceptable cost or at least 
obtain the cost associated with the chosen path).
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, then somebody is doing something 
redundant, and there is a possibility for error.  In practice, a package or 
library that declares two interfaces should provide the adapter between 
them, if a sensible one can exist.  For two separate packages, ordinarily 
one is the client and needs to adapt from one of its own implementations or 
interfaces to a foreign interface, or vice versa, and in either case the 
client should be the registrant for the adapters.

Bridging between two foreign packages is the only case in which there is an 
actual possibility of having two packages attempt to bridge the exact same 
interfaces or implementations, and this case is very rare, at least at 
present.  Given the extreme rarity of this legitimate situation where two 
parties have independently created adapter paths of the same length and 
number of adapters between two points, I considered it better to consider 
the situation an error, because in the majority of these bridging cases, 
the current author is the one who created at least one of the bridges, in 
which case he now knows that he is creating a redundant adapter that he 
need no longer maintain.

The very rarest of all scenarios would be that the developer is using two 
different packages that both bridge the same items between two *other* 
packages.  This is the only scenario I can think of where would be a 
duplication that the current developer could not easily control, and the 
only one where PyProtocols' current policy would create a problem for the 
developer, requiring them to explicitly work around the issue by declaring 
an artificially "better" adapter path to resolve the ambiguity.

As far as I can tell, this scenario will remain entirely theoretical until 
there are at least two packages out there with interfaces that need 
bridging, and two more packages exist that do the bridging, that someone 
might want to use at the same time.  I think that this will take a while.  :)

In the meantime, all other adapter ambiguities are suggestive of a possible 
programming or design error, such as using interface inheritance to denote 
what an interface requires instead of what it provides, incorrectly 
claiming that something is a universal (interface-to-interface) adapter 
when it is only suitable for certain concrete classes, etc.


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 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.


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 declare 
that one interface implies another isn't a big deal.

Such a practice might seem very strange to Java programers, however, since 
it means that if you declare (in Python) a method to take IBa

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 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 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 10:16 AM 1/12/05 -0800, Guido van Rossum wrote:
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.
Another possibility; I've realized from Alex's last mail that there's a 
piece of my reasoning that I haven't been including, and now I can actually 
explain it clearly (I hope).  In my view, there are at least two kinds of 
adapters, with different fidelity requirements/difficulty:

   class -> interface  ("lo-fi" is okay)
   interface -> interface  (It better be perfect!)
If you cannot guarantee that your interface-to-interface adapter is the 
absolute best way to adapt *any* implementation of the source interface, 
you should *not* treat it as an interface-to-interface adapter, but rather 
as a class-to-interface adapter for the specific classes that need 
it.  And, if transitivity exists, it is now restricted to a sensible subset 
of the possible paths.

I believe that this difference is why I don't run into Alex's problems in 
practice; when I encounter a use case like his, I may write the same 
adapter, but I'll usually register it as an adapter from 
class-to-interface, if I need to register it for implicit adaptation at all.

Also note that the fact that it's harder to write a solid 
interface-to-interface adapter naturally leads to my experience that 
transitivity problems occur more often via interface inheritance.  This is 
because interface inheritance as implemented by both Zope and PyProtocols 
is equivalent to defining an interface-to-interface adapter, but with no 
implementation!  Obviously, if it is already hard to write a good 
interface-to-interface adapter, then it must be even harder when you have 
to do it with no actual code!  :)

I think maybe this gets us a little bit closer to having a unified (or at 
least unifiable) view on the problem area.  If Alex agrees that 
class-to-interface adaptation is an acceptable solution for limiting the 
transitivity of noisy adaptation while still allowing some degree of 
implicitness, then maybe we have a winner.

(Btw, the fact that Zope and Twisted's interface systems initially 
implemented *only* interface-to-interface adaptation may have also led to 
their conceptualizing transitivity as unsafe, since they didn't have the 
option of using class-to-interface adapters as a way to deal with more 
narrowly-applicable adaptations.)

___
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: getting special from type, not instance (was Re: [Python-Dev] copy confusion)

2005-01-12 Thread Aahz
On Wed, Jan 12, 2005, Guido van Rossum wrote:
>
> PS. The term "data descriptor" now feels odd, perhaps we can say "hard
> descriptors" instead. Hard descriptors have a __set__ method in
> addition to a __get__ method (though the __set__ method may always
> raise an exception, to implement a read-only attribute).

I'd prefer "property descriptor" since that's the primary use case.
"Getset descriptor" also works for me.
-- 
Aahz ([EMAIL PROTECTED])   <*> http://www.pythoncraft.com/

"19. A language that doesn't affect the way you think about programming,
is not worth knowing."  --Alan Perlis
___
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 James Y Knight
I'd just like to share a use case for transitive adaption that I've 
just run into (I'm using Zope.Interface which does not support it). 
Make of this what you will, I just thought an actual example where 
transitive adaption is actually necessary might be useful to the 
discussion.

I have a framework with an interface 'IResource'. A number of classes 
implement this interface. I introduce a new version of the API, with an 
'INewResource', so I register a wrapping adapter from 
IResource->INewResource in the global adapter registry.

This all works fine as long as all the old code returns objects that 
directly provide IResource. However, the issue is that code working 
with the old API *doesn't* just do that, it may also have returned 
something that is adaptable to IResource. Therefore, calling 
INewResource(obj) will fail, because there is no direct adapter from 
obj to INewResource, only obj->IResource and IResource->INewResource.

Now, I can't just add the extra adapters from obj->INewResource myself, 
because the adapter from obj->IResource is in client code, 
compatibility with which is needed. So, as far as I can tell, I have 
two options:
1) everywhere I want to adapt to INewResource, do a dance:

resource = INewResource(result, None)
if resource is not None:
  return resource
resource = IResource(result, None)
if resource is not None:
  return INewResource(resource)
else:
  raise TypeError("blah")
2) Make a custom __adapt__ on INewResource to do similar thing. This 
seems somewhat difficult with zope.interface (need two classes) but 
does work.

class INewResource(zope.interface.Interface):
pass
class SpecialAdaptInterfaceClass(zope.interface.InterfaceClass):
def __adapt__(self, result):
resource = zope.interface.InterfaceClass.__adapt__(self, other)
if resource is not None:
return resource
resource = IResource(result, None)
if resource is not None:
return INewResource(result)
INewResource.__class__ = SpecialAdaptInterfaceClass

I chose #2. In any case, it certainly looks doable, even with a 
non-transitive adaptation system, but it's somewhat irritating. 
Especially if you end up needing to do that kind of thing often.

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-12 Thread Phillip J. Eby
At 07:04 PM 1/12/05 +0100, Alex Martelli wrote:
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!
Indeed!
Let me try and be more specific about my assumptions.  What *I* would do in 
your described scenario is *not* register a general-purpose IPerson -> 
IFullName adapter, because in the general case this is a lossy adaptation.

However, for some *concrete* types an adaptation to IFullName must 
necessarily have a NULL middle name; therefore, I would define a *concrete 
adaptation* from those types to IFullName, *not* an adaptation from IPerson 
-> IFullName.  This still allows for transitive adapter composition from 
IFullName on to other interfaces, if need be.

IOW, the standard for "purity" in adapting from a concrete type to an 
interface can be much lower than for adapting from interface to 
interface.  An interface-to-interface adapter is promising that it can 
adapt any possible implementation of the first interface to the second 
interface, and that it's always suitable for doing so.  IMO, if you're not 
willing to make that commitment, you shouldn't define an 
interface-to-interface adapter.

Hm.  Maybe we actually *agree*, and are effectively only arguing 
terminology?  That would be funny, yet sad.  :)


  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.
Sorry; I think of "noisy adaptation" as being "conversion" -- i.e. I have 
one mental bucket for all conversion/adaptation scenarios that aren't "pure 
as-a" relationships.


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*?!?!
See above.  I thought this was obvious; sorry for the confusion.
I think we may be getting close to a breakthrough, though; so let's hang in 
there a bit longer.

___
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:26 AM 1/12/05 -0800, 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.
Alex has suggested that there be a way to indicate that an adapter is 
noiseless and therefore suitable for transitivity.

I, on the other hand, would prefer having a way to declare that an adapter 
is *unsuitable* for transitivity, in the event that you feel the need to 
introduce an "imperfect" implicit adapter (versus using an explicit 
conversion).

So, in principle we agree, but we differ regarding what's a better 
*default*, and this is probably where you will be asked to Pronounce, 
because as Alex says, this *is* controversial.

However, I think there is another way to look at it, in which *both* can be 
the default...

Look at it this way.  If you create an adapter class or function to do some 
kind of adaptation, it is not inherently transitive, and you have to 
explicitly invoke it.  (This is certainly the case today!)

Now, let us say that you then register that adapter to perform implicit 
adaptation -- and by default, such a registration says that you are happy 
with it being used implicitly, so it will be used whenever you ask for its 
target interface or some further adaptation thereof.

So, here we have a situation where in some sense, BOTH approaches are the 
"default", so in theory, both sides should be happy.

However, as I understand it, Alex is *not* happy with this, because he 
wants to be able to register a noisy adapter for *implicit* use, but only 
in the case where it is used directly.

The real question, then, is "What is that use case good for?"  And I don't 
have an answer to that question, because it's Alex's use case.

I'm proposing an approach that has two useful extremes: be noisy and 
explicit, or clean and implicit.  Alex seems to want to also add the middle 
ground of "noisy but implicit", and I think this is a bad idea because it 
will lead to precisely to the same problems as it does in C++!

Python as it exists today tends to support the proposition that noisy 
adaptation or conversion should not be implicit, since trying to do 
'someList[1.2]' raises a TypeError, rather than silently truncating.  The 
number of steps between 'float' and 'int' in some adaptation graph has 
absolutely nothing to do with it; even if there is only one step, doing 
this kind of conversion or adaptation implicitly is just a bad idea.

___
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: getting special from type, not instance (was Re: [Python-Dev] copy confusion)

2005-01-12 Thread Phillip J. Eby
At 09:59 AM 1/12/05 -0800, Guido van Rossum wrote:
We would need to introduce a new decorator so that classes overriding
these methods can also make those methods "data descriptors", and so
that users can define their own methods with this special behavior
(this would be needed for __copy__, probably).
I have used this technique as a workaround in PyProtocols for __conform__ 
and __adapt__, so I know it works.  In fact, here's the implementation:

def metamethod(func):
"""Wrapper for metaclass method that might be confused w/instance 
method"""
return property(lambda ob: func.__get__(ob,ob.__class__))

Basically, if I implement a non-slotted special method (like __copy__ or 
__getstate__) on a metaclass, I usually wrap it with this decorator in 
order to avoid the "metaconfusion" issue.

I didn't mention it because the technique had gotten somehow tagged in my 
brain as a temporary workaround until __conform__ and __adapt__ get slots 
of their own, rather than a general fix for metaconfusion.  Also, I wrote 
the above when Python 2.2 was still pretty new, so its applicability was 
somewhat limited by the fact that 2.2 didn't allow super() to work with 
data descriptors.  So, if you used it, you couldn't use super.  This 
probably isn't a problem any more, although I'm still using the super-alike 
that I wrote as a workaround, so I don't know for sure.  :)


PS. The term "data descriptor" now feels odd, perhaps we can say "hard
descriptors" instead. Hard descriptors have a __set__ method in
addition to a __get__ method (though the __set__ method may always
raise an exception, to implement a read-only attribute).
I think I'd prefer "Override descriptor" to "Hard descriptor", but either 
is better than data descriptor.  Presumably there will need to be backward 
compatibility macros in the C API, though for e.g. PyDescriptor_IsData or 
whatever it's currently called.

___
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] Feed style codec API

2005-01-12 Thread Walter Dörwald
Now that Python 2.4 is out the door (and the problems with
StreamReader.readline() are hopefully fixed), I'd like bring
up the topic of a feed style codec API again. A feed style API
would make it possible to use stateful encoding/decoding where
the data is not available as a stream.
Two examples:
- xml.sax.xmlreader.IncrementalParser: Here the client passes raw
  XML data to the parser in multiple calls to the feed() method.
  If the parser wants to use Python codecs machinery, it has to
  wrap a stream interface around the data passed to the feed()
  method.
- WSGI (PEP 333) specifies that the web application returns the
  fragments of the resulting webpage as an iterator. If this result
  is encoded unicode we have the same problem: This must be wrapped
  in a stream interface.
The simplest solution is to add a feed() method both to StreamReader
and StreamWriter, that takes the state of the codec into account,
but doesn't use the stream. This can be done by simply moving a
few lines of code into separate methods. I've uploaded a patch to
Sourceforge: #1101097.
There are other open issues with the codec changes: unicode-escape,
UTF-7, the CJK codecs and probably a few others don't support
decoding imcomplete input yet (although AFAICR the functionality
is mostly there in the CJK codecs).
Bye,
   Walter Dörwald
___
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


[Python-Dev] Re: Recent IBM Patent releases

2005-01-12 Thread Scott David Daniels
Skip Montanaro wrote:
Who is going to decide if a particular library would be affected by one or
more of the 500 patents IBM released?
Skip
I am thinking more along the lines of, "our policy on accepting new code
[will/will not] be to allow new submissions which use some of that
patented code."  I believe our current policy is that the author
warrants that the code is his/her own work and not encumbered by
any patent.
-- Scott David Daniels
[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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Michael Chermside
I wrote:
> I don't see how [LiskovViolation could have a more descriptive name].
> Googling on Liskov immediately brings up clear and understandable
> descriptions of the principle


David writes:
> Clearly, I disagree. [...]

Skip writes:
> I had never heard the term before and consulted the Google oracle as well.

This must be one of those cases where I am mislead by my background...
I thought of Liskov substitution principle as a piece of basic CS
background that everyone learned in school (or from the net, or wherever
they learned programming). Clearly, that's not true.

Guido writes:
> How about SubstitutabilityError?

It would be less precise and informative to ME but apparently more so
to a beginner. Obviously, we should support the beginner!

-- 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-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] Recent IBM Patent releases

2005-01-12 Thread Skip Montanaro

Scott> Since this includes patents on compression and encryption stuff,
Scott> we will definitely be faced with deciding on whether to allow use
Scott> of these patents in the main Python library.

Who is going to decide if a particular library would be affected by one or
more of the 500 patents IBM released?

Skip
___
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] Re: PEP 246: LiskovViolation as a name

2005-01-12 Thread Skip Montanaro

>>> 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.

David> Clearly, I disagree.

I had never heard the term before and consulted the Google oracle as well.
I found this more readable definition:

Functions that use pointers or references to base classes must be able to
use objects of derived classes without knowing it.

here:

http://www.compulink.co.uk/~querrid/STANDARD/lsp.htm

Of course, the situations in which a Liskov violation can occur can be a bit
subtle.

David> My point is that it'd be nice if we could come up with an
David> exception name which could be grokkable without requiring 1)
David> Google, 2) relatively high-level understanding of type theory.

I suspect if there was a succinct way to convey the concept in two or three
words it would already be in common use.  The alternative seems to be to
make sure it's properly docstringed and added to the tutorial's glossary:

>>> help(lv.LiskovViolation)
Help on class LiskovViolation in module lv:

class LiskovViolation(exceptions.Exception)
 |  Functions that use pointers or references to base classes must be
 |  able to use objects of derived classes without knowing it.
 |  
 ...

I suspect there's something to be said for exposing the user base to a
little bit of software engineering terminology every now and then.  A couple
years ago I suspect most of us had never heard of list comprehensions, and
we all bat the term about without a second thought now.

Skip
___
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] Re: [Csv] csv module and universal newlines

2005-01-12 Thread Skip Montanaro

Andrew> The csv parser consumes lines from an iterator, but it also has
Andrew> it's own idea of end-of-line conventions, which are currently
Andrew> only used by the writer, not the reader, which is a source of
Andrew> much confusion. The writer, by default, also attempts to emit a
Andrew> \r\n sequence, which results in more confusion unless the file
Andrew> is opened in binary mode.

Andrew> I'm looking for suggestions for how we can mitigate these
Andrew> problems (without breaking things for existing users).

You can argue that reading csv data from/writing csv data to a file on
Windows if the file isn't opened in binary mode is an error.  Perhaps we
should enforce that in situations where it matters.  Would this be a start?

terminators = {"darwin": "\r",
   "win32": "\r\n"}

if (dialect.lineterminator != terminators.get(sys.platform, "\n") and
   "b" not in getattr(f, "mode", "b")):
   raise IOError, ("%s not opened in binary mode" %
   getattr(f, "name", "???"))

The elements of the postulated terminators dictionary may already exist
somewhere within the sys or os modules (if not, perhaps they should be
added).  The idea of the check is to enforce binary mode on those objects
that support a mode if the desired line terminator doesn't match the
platform's line terminator.

Skip
___
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: getting special from type, not instance (was Re: [Python-Dev] copy confusion)

2005-01-12 Thread Guido van Rossum
[Alex]
> Armin's fix was to change:
> 
> conform = getattr(type(obj), '__conform__', None)
> 
> into:
> 
> for basecls in type(obj).__mro__:
> if '__conform__' in basecls.__dict__:
> conform = basecls.__dict__['__conform__']
> break
> else:
> # not found
> 
> I have only cursorily examined the rest of the standard library, but it
> seems to me there may be a few other places where getattr is being used
> on a type for this purpose, such as pprint.py which has a couple of
> occurrences of
>  r = getattr(typ, "__repr__", None)
[And then proceeds to propose a new API to improve the situation]

I wonder if the following solution wouldn't be more useful (since less
code will have to be changed).

The descriptor for __getattr__ and other special attributes could
claim to be a "data descriptor" which means that it gets first pick
*even if there's also a matching entry in the instance __dict__*.
Quick illustrative example:

>>> class C(object):
 foo = property(lambda self: 42)   # a property is always a "data
descriptor"

>>> a = C()
>>> a.foo
42
>>> a.__dict__["foo"] = "hello"
>>> a.foo
42
>>> 

Normal methods are not data descriptors, so they can be overridden by
something in __dict__; but it makes some sense that for methods
implementing special operations like __getitem__ or __copy__, where
the instance __dict__ is already skipped when the operation is invoked
using its special syntax, it should also be skipped by explicit
attribute access (whether getattr(x, "__getitem__") or x.__getitem__
-- these are entirely equivalent).

We would need to introduce a new decorator so that classes overriding
these methods can also make those methods "data descriptors", and so
that users can define their own methods with this special behavior
(this would be needed for __copy__, probably).

I don't think this will cause any backwards compatibility problems --
since putting a __getitem__ in an instance __dict__ doesn't override
the x[y] syntax, it's unlikely that anybody would be using this.
"Ordinary" methods will still be overridable.

PS. The term "data descriptor" now feels odd, perhaps we can say "hard
descriptors" instead. Hard descriptors have a __set__ method in
addition to a __get__ method (though the __set__ method may always
raise an exception, to implement a read-only attribute).

-- 
--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] Re: [Csv] csv module TODO list

2005-01-12 Thread Skip Montanaro

Raymond> Would the csv module be a good place to add a DBF reader and
Raymond> writer?

Not really.

Raymond> I've posted a draft on ASPN.  It interoperates well with the
Raymond> rest of the CSV module because it also accepts/returns a list
Raymond> of fieldnames and a sequence of records.

Raymond> http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/362715

Just clean it up (do the doco thing) and check it in as dbf.py with reader
and writer functions.

I see your modus operandi at work: code something in Python then switch to C
when nobody's looking. ;-)

Skip

___
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


[Python-Dev] Re: logging class submission

2005-01-12 Thread Vinay Sajip
There is already a TimedRotatingFileHandler which will do backups on a
schedule, including daily.
The correct way of doing what you want is to submit a patch via
SourceForge. If the patch is accepted, then your code will end up in Python.
Thanks,
Vinay Sajip
___
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] Recent IBM Patent releases

2005-01-12 Thread Scott David Daniels
IBM has recently released 500 patents for use in opensource code.
http://www.ibm.com/ibm/licensing/patents/pledgedpatents.pdf
"...In order to foster innovation and avoid the possibility that a
party will take advantage of this pledge and then assert patents or
other intellectual property rights of its own against Open Source
Software, thereby limiting the freedom of IBM or any other Open
Source developer to create innovative software programs, the
commitment not to assert any of these 500 U.S. patents and all
counterparts of these patents issued in other countries is
irrevocable except that IBM reserves the right to terminate this
patent pledge and commitment only with regard to any party who files
a lawsuit asserting patents or other intellectual property rights
against Open Source Software."
Since this includes patents on compression and encryption stuff, we
will definitely be faced with deciding on whether to allow use of these
patents in the main Python library.
Somebody was worried about BSD-style licenses on Groklaw, and said,
"Yes, you can use this patent in the free version... but if you
close the code, you're violating IBM's Patents, and they WILL come
after you. Think of what would have happened if IBM had held a
patent that was used in the FreeBSD TCP/IP stack?  Microsoft used
it as the base of the Windows NT TCP/IP stack. IBM could then sue
Microsoft for patent violations."
To which he got the following reply:
"Sorry, but that's not correct. That specific question was asked
on the IBM con-call about this announcement. i.e. if there were a
commercial product that was a derived work of an open source
project that used these royalty-free patents, what would happen?
"IBM answered that, so long as the commercial derived work followed
the terms of the open source license agreement, there was no
problem. (So IBM is fine with a commercial product based on an
open source BSD project making use of these patents.)"
This means to me we can put these in Python's library, but it is
definitely something to start deciding now.
-- Scott David Daniels
[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 Michael Chermside
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.

Converting LotsOfInfo to FullName via PersonName results in None for the
middle name. But that's just not right... it _should_ be filling in the
middle initial because that information IS available. It's technically
correct in a theoretical sort of a way (FullName never PROMISES that
middle_initial will be available), but it's wrong in a my-program-doesn't-
work-right sort of way, because it HAS the information available yet
doesn't use it.

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. I can explicitly silence it by registering a trivial
converter:

def adapt_LotsOfInfo_to_FullName(lots_of_info):
person_name = adapt(lots_of_info, PersonName)
return adapt(person_name, FullName)

but if it just worked, I could only discover that by being clever enough
to think of writing unit test for middle name.

--

Elsewhere, Phillip writes:
> If you derive an interface from another interface, this is supposed to mean
> that your derived interface promises to uphold all the promises of the base
> interface.  That is, your derived interface is always usable where the base
> interface is required.
>
> However, oftentimes one mistakenly derives an interface from another while
> meaning that the base interface is *required* by the derived interface,
> which is similar in meaning but subtly different.  Here, you mean to say,
> "IDerived has all of the requirements of IBase", but you have instead said,
> "You can use IDerived wherever IBase is desired".

Okay, that's beginning to make sense to me.

> 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.

--

Alex summarizes nicely:
> 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
  [...]
> Much the same applies to inheritance, BTW, which as PJE has pointed out
> a few times also induces transitivity in adaptation, and, according to
> him, is a more likely cause of bugs than chains of adapters

But Alex goes on to say that perhaps we need two grades of adaptations
(perfect and real-world) and two grades of interface inheritance (perfect
and otherwise) so that the transitivity can be (automatically) invoked
only for the perfect ones. That feels to me like excessive complexity:
why not just prohibit transitivity? What, after all, is the COST of
prohibiting transitivity?

For the first case (adapter chains) the cost is a N^2 explosion in the
number of adapters needed. I said I thought that N would be small, but
Phillip (who knows what he's talking about, don't get me wrong here)
says that it's big enough to be mildly annoying at times to Twisted
and Eclipse developers.

For the second case (interface inheritance), I haven't yet thought
through clearly how at affects things... in fact, it sort of seems like
there's no good way to _prevent_ "transitivity" in this case short
of prohibiting interface inheritance entirely. And, as Phillip points
out to me (see above) this is a more common type of error.

Gee... I'm understanding the problem a little better, but elegant
solutions are still escaping me.

-- 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-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 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!

___
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] PATCH/RFC for AF_NETLINK support

2005-01-12 Thread David Wilson
On Tue, Jan 11, 2005 at 02:15:23PM +, Jp Calderone wrote:

> > I would like to see (optional?) support for this before your patch is
> > merged. I have a long-term interest in a Python-based service control /
> > init replacement / system management application, for use in specialised
> > environments. I could definately use this. :)
> 
>   Useful indeed, but I'm not sure why basic NETLINK support should be 
> held up for it?

Point taken. I don't recall why I thought special code would be required
for this.

I was thinking a little more about how support might be added for older
kernels. No harm can be done by compiling in the constant, and it
doesn't cost much. How about:

#include 
...

#ifndef NETLINK_KOBJECT_UEVENT
#define NETLINK_KOBJECT_UEVENT  15
#endif

/* Code assuming build host supports KOBJECT_UEVENT. */


Type thing.

Cheers,


David.

-- 
... do you think I'm going to waste my time trying to pin physical
interpretations upon every optical illusion of our instruments? Since when
is the evidence of our senses any match for the clear light of reason?
-- Cutie, in Asimov's Reason
___
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:49, 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? 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).
Very good point -- thanks Phillip and Guido jointly for pointing this 
out.

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 16:45, Guido van Rossum wrote:
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.
Ah, this is the crucial point: an explicit adapter must take precedence 
over substitutability that is assumed by subclassing.  From my POV this 
does just as well as any other kind of explicit control about whether 
subclassing implies substitutability.

In retrospect, that's the same strategy as in copy.py: *FIRST*, check 
the registry -- if something is found in the registry, THAT takes 
precedence.  *THEN*, only for cases where the registry doesn't give an 
answer, proceed with other steps and checks and sub-strategies.

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)].  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.

I intend to restructure pep246 at next rewrite to reflect this "obvious 
once thought of" idea, and thanks, Guido, for providing 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: 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: 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: [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: [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 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


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 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


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 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 Alex Martelli
On 2005 Jan 12, at 15:00, Paul Moore wrote:
On Wed, 12 Jan 2005 00:33:22 +0100, Alex Martelli <[EMAIL PROTECTED]> 
wrote:
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.
[...]
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.
I know this is out-of-context picking, but I don't think I've ever
seen anyone state that A->?->C is "just as good as" a direct A->C. I
would have thought it self-evident that a shorter adaptation path is
always better. And specifically, I know that Philip has stated that
PyProtocols applies a shorter-is-better algorithm.
Yes, he has.  If A->C is registered as a direct adaptation, it gets 
used and everybody lives happily ever after.  The controversy comes 
when A->C is *NOT* registered as a direct adaptation.

If there is no degradation of information quality, etc, at any 
intermediate step, picking the shortest path is still sensible because 
of likely performance consideration.  Each adaptation step might put 
some kind of wrapper/proxy/adapter object in the mix, delegate calls, 
etc.  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.

Demanding that the set of paths of minimal available length has exactly 
one element is strange, though, IF one is assuming that all adaptation 
paths are exactly equivalent except at most for secondary issues of 
performance (which are only adjudicated by the simplest heuristic: if 
those issues were NOT considered minor/secondary, then a more 
sophisticated scheme would be warranted, e.g. by letting the programmer 
associate a cost to each step, picking the lowest-cost path, AND 
letting the caller of adapt() also specify the maximal acceptable cost 
or at least obtain the cost associated with the chosen path).

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).

Even C++ at least lets a poor beleaguered programmer assert that a 
conversion (C++ does not have adaptation, but it does have conversion) 
is _EXPLICIT_, meaning that it only applies as a single isolated step 
and NOT as a part of one of those automatic transitive 
conversion-chains which so often produce amazing, hell-to-debug 
results.  That's the wrong default (explicit should be the default, 
"usable transitively" should need to be asserted outright), explainable 
by the usual historical and backwards compatibilty reason (just like 
having methods default to non-virtual, etc, etc), but at least it's 
THERE -- a way to stop transitivity and restore sanity.  I have not yet 
seen PJE willing to compromise on this point -- having two categories 
or grades of adaptations, one "perfect, lossless, noiseless, 
impeccable" usable transitively and one "sublunar" NOT usable 
transitively.  ((If he was, we could still argue on which one should be 
the default;-))

Much the same applies to inheritance, BTW, which as PJE has pointed out 
a few times also induces transitivity in adaptation, and, according to 
him, is a more likely cause of bugs than chains of adapters (I have no 
reason to doubt that any way to induce transitivity without very 
clearly stating that one WANTS that effect can be extremely bug-prone).

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''.  Here, regretfully, I'll admit C++ has the advantage, since 
``private inheritance'' is exactly that inferior, implementation-only 
kind (I'm perfectly happy with Python NOT having private methods nor 
attributes, but private INHERITANCE sometimes I still miss;-).  Ah 
well, can't have everything.  While I hope we can offer 

Re: [Python-Dev] PEP 246, redux

2005-01-12 Thread Mark Russell
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,
  add a way to say  "this adaptor can be used as part of a
  transitive chain"

Mark Russell

___
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 Paul Moore
On Wed, 12 Jan 2005 00:33:22 +0100, Alex Martelli <[EMAIL PROTECTED]> wrote:
> 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.
[...]
> 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.

I know this is out-of-context picking, but I don't think I've ever
seen anyone state that A->?->C is "just as good as" a direct A->C. I
would have thought it self-evident that a shorter adaptation path is
always better. And specifically, I know that Philip has stated that
PyProtocols applies a shorter-is-better algorithm.

Having pointed this out, I'll go back to lurking. You two are doing a
great job of converging on something so far, so I'll let you get on
with it.

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-12 Thread Paul Moore
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.

Are you mistakenly thinking that shortest-possible-route semantics
aren't used? Maybe the PEP should explicitly require such semantics.

If I'm missing the point here, I apologise. But I get the feeling that
something's getting lost in the discussions.

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-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] Re: copy confusion

2005-01-12 Thread Alex Martelli
On 2005 Jan 12, at 00:30, Fredrik Lundh wrote:
Guido van Rossum wrote:
The only thing this intends to break /.../
it breaks classic C types:
True!!!  And it only breaks copy, NOT deepcopy, because of the 
following difference between the two functions in copy.py...:

def deepcopy(x, memo=None, _nil=[]):
   ...
cls = type(x)
copier = _deepcopy_dispatch.get(cls)
if copier:
y = copier(x, memo)
else:
try:
issc = issubclass(cls, type)
except TypeError: # cls is not a class (old Boost; see SF 
#502085)
issc = 0
if issc:
y = _deepcopy_atomic(x, memo)
else:
copier = getattr(x, "__deepcopy__", None)

Now:
>>> x = cElementTree.Element("tag")
>>> cls = type(x)
>>> issubclass(cls, type)
False
therefore, copy.deepcopy ends up doing the getattr of '__deepcopy__' on 
x and live happily ever after.  Function copy.copy does NOT do that 
issubclass check, therefore it breaks Fredrik's code.


(and of course,  custom C types is the only case where I've ever used
__copy__; the default behavior has worked just fine for all other 
cases)

for cElementTree, I've worked around this with an ugly __reduce__ hack,
but that doesn't feel right...
I think you're entirely correct and that we SHOULD bugfix copy.py so 
that function copy, just like function deepcopy, does the getattr from 
the object when not issubclass(cls, type).

The comment suggests that check is there only for strange cases such as 
"old Boost" (presumably Boost Python in some previous incarnation) but 
it appears to me that it's working fine for your custom C type and that 
it would work just as well for __copy__ as is seems to do for 
__deepcopy__.

The fix, again, should be a tiny patch -- and it seems to me that we 
should have it for 2.3.5 as well as for 2.4.1 and the HEAD.

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


[Python-Dev] PyOS_InputHook and threads

2005-01-12 Thread Michiel Jan Laurens de Hoon
I have started writing a patch that replaces PyOS_InputHook with 
PyOS_AddInputHook and PyOS_RemoveInputHook. I am a bit confused though on how 
hook functions are supposed to work with threads.

PyOS_InputHook is a pointer to a hook function, which can be defined for example 
in a C extension module.

When Python is running in a single thread, PyOS_InputHook is called ten times 
per second while Python is waiting for the user to type something. This is 
achieved by setting readline's rl_event_hook function to PyOS_InputHook.

When Python uses multiple threads, each thread has its own PyOS_InputHook (I am 
not sure if this was intended). However, with IDLE I noticed that the subprocess 
thread doesn't call its PyOS_InputHook. In IDLE (if I understand correctly how 
it works), one thread takes care of the GUI and the interaction with the user, 
while another thread executes the user's commands. If an extension module sets 
PyOS_InputHook, the PyOS_InputHook belonging to this second thread is set. 
However, this PyOS_InputHook does not get called. Is this simply an oversight? 
What would be a suitable place to add the call to PyOS_InputHook? In other 
words, where does the second thread go idle?

--Michiel.

On Thu, Dec 09, 2004, Michiel Jan Laurens de Hoon wrote:
My suggestion is therefore to replace PyOS_InputHook by two functions
PyOS_AddInputHook and PyOS_RemoveInputHook, and let Python keep track of
which hooks are installed. This way, an extension module can add a hook
function without having to worry about other extension modules trying
to use the same hook.
Any comments? Would I need to submit a PEP for this proposal?

Because this is only for the C API, your best bet is to write a patch
and submit it to SF.  If people whine or it gets rejected, then write a
PEP.

--
Michiel de Hoon, Assistant Professor
University of Tokyo, Institute of Medical Science
Human Genome Center
4-6-1 Shirokane-dai, Minato-ku
Tokyo 108-8639
Japan
http://bonsai.ims.u-tokyo.ac.jp/~mdehoon
___
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


getting special from type, not instance (was Re: [Python-Dev] copy confusion)

2005-01-12 Thread Alex Martelli
Since this bug isn't the cause of Fredrik's problem I'm changing the 
subject (and keep discussing the specific problem that Fredrik 
uncovered under the original subject).

On 2005 Jan 12, at 05:11, Guido van Rossum wrote:
   ...
I had exactly the same metabug in the pep 246 reference 
implementation,
Armin Rigo showed how to fix it in his only recent post.
Don't recall seeing that, but if you or he can fix this without
breaking other stuff, it's clear you should go ahead. (This worked in
2.2, FWIW; it broke in 2.3.)
Armin's fix was to change:
   conform = getattr(type(obj), '__conform__', None)
into:
   for basecls in type(obj).__mro__:
   if '__conform__' in basecls.__dict__:
   conform = basecls.__dict__['__conform__']
   break
   else:
   # not found
I have only cursorily examined the rest of the standard library, but it 
seems to me there may be a few other places where getattr is being used 
on a type for this purpose, such as pprint.py which has a couple of 
occurrences of
r = getattr(typ, "__repr__", None)

Since this very same replacement is needed in more than one place for 
"get the following special attribute from the type of the object', it 
seems that a function to do it should be introduced in one place and 
used from where it's needed:

def get_from_first_dict(dicts, name, default=None):
   for adict in dicts:
   try:
   return adict[name]
   except KeyError:
   pass
   return default
to be called, e.g. in the above example with '__conform__', as:
conform = get_from_first_dict(
  (basecls.__dict__ for basecls in type(obj).__mro__),
  '__conform__'
  )
The needed function could of course be made less general, by giving 
more work to the function and less work to the caller, all the way down 
to:

def getspecial(obj, name, default=None):
   for basecls in type(obj).__mro__:
   try:
   return basecls.__dict__[name]
   except KeyError:
   pass
   return default
to be called, e.g. in the above example with '__conform__', as:
conform = getspecial(obj, '__conform__')
This has the advantage of not needing the genexp, so it's usable to 
implement the fix in 2.3.5 as well as in 2.4.1.  Moreover, it can 
specialcase old-style class instances to provide the backwards 
compatible behavior, if desired -- that doesn't matter (but doesn't 
hurt) to fix the bug in copy.py, because in that case old-style 
instances have been already specialcases previously, and might help to 
avoid breaking anything in other similar bugfixes, so that's what I 
would suggest:

def getspecial(obj, name, default=None):
   if isinstance(obj, types.InstanceType):
   return getattr(obj, name, default)
   for basecls in type(obj).__mro__:
   try:
   return basecls.__dict__[name]
   except KeyError:
   pass
   return default
The tradeoff between using type(obj) and obj.__class__ isn't 
crystal-clear to me, but since the latter might apparently be faked by 
some proxy to survive isinstance calls type(obj) appears to me to be 
right.

Where in the standard library to place this function is not clear to me 
either.  Since it's going into bugfix-only releases, I assume it 
shouldn't be "published".  Maybe having it as copy._getspecial (i.e. 
with a private name) is best, as long as it's OK to introduce some 
coupling by having (e.g.) pprint call copy._getspecial too.

Performance might be a problem, but the few bugfix locations where a 
getattr would be replaced by this getspecial don't seem to be hotspots, 
so maybe we don't need to worry about it for 2.3 and 2.4 (it might be 
nice to have this functionality "published" in 2.5, of course, and then 
it should probably be made fast).

Feedback welcome -- the actual patch will doubtless be tiny, but it 
would be nice to have it right the first time (as it needs to go into 
both the 2.3 and 2.4 bugfix branches and the 2.5 head).

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