Re: [Python-Dev] PEP 246, Feedback Request

2005-01-16 Thread Guido van Rossum
   - protocol means any object, usually a type or class or interface,
 which guides the construction of an adapter

Then what do we call the abstract *concept* of a protocol?

 - adaptee-class refers to the adaptee's class

Please make it explicit that this is a.__class__, not type(a).

   - factory refers to a function, f(adaptee) - adapter, where
 the resulting adapter complies with a given protocol

Make this adapter factory -- factory by itself is too commonly used.

   - First, the registry is checked for a suitable adapter

How about checking whether adaptee.__class__ is equal to the protocol
even before this?  It would be perverse to declare an adapter from a
protocol to itself that wasn't the identity adapter.

   - PEP 246 will ask for a `adapt' module, with an `adapt' function.

Please don't give both the same name.  This practice has caused enough
problems in the past.  The module can be called adaptation, or
adapting (cf. threading; but it doesn't feel right so I guess
adaptation is better).

   - At any stage of adaptation, if None is returned, the adaptation
 continues to the next stage.

Maybe use NotImplemented instead?  I could imagine that occasionally
None would be a valid adapter.  (And what do we do when asked adapt
None to a protocol?  I think it should be left alone but not
considered an error.)

   - At any stage of adaption, if adapt.AdaptException(TypeError) is
 raised, then the adaptation process stops, as if None had been
 returned from each stage.

Why are there two ways to signal an error?  TOOWTDI!

   - One can also register a None factory from A-B for the
 purpose of marking it transitive.  In this circumstance,
 the composite adapter is built through __conform__ and
 __adapt__.  The None registration is just a place holder
 to signal that a given path exists.

Sounds overkill; the None feels too magical.  An explicit adapter
can't be too difficult to come up with?

 There is a problem with the default isinstance() behavior when
 someone derives a class from another to re-use implementation,
 but with a different 'concept'.  A mechanism to disable
 isinstance() is needed for this particular case.

Do we really have to care about this case?  Has someone found that
things go harebrained when this case is not handled?  It sounds very
much like a theoretical problem only.  I don't mean that subclasses
that reuse implementation without being substitutable are rare (I've
seen and written plenty); I mean that I don't expect this to cause
additional problems due to incorrect adaptation.

 Guido would like his type declaration syntax (see blog entry) to
 be equivalent to a call to adapt() without any additional
 arguments.  However, not all adapters should be created in the
 context of a declaration -- some should be created more
 explicitly.  We propose a mechanism where an adapter factory can
 register itself as not suitable for the declaration syntax.

I'm considering a retraction of this proposal, given that adaptation
appears to be so subtle and fraught with controversies and pitfalls;
but more particularly given the possible requirement (which someone
added in a response to a blog) that it should be possible to remove or
ignore type declarations without changing the meaning of programs that
run correctly (except for code that catches TypeError).

   - adapt( , intrinsic_only = False) will enable both sorts of adapters,

That's one ugly keyword parameter.  If we really need this, I'd like
to see something that defaults to False and can be switched on by
passing mumble=True on the call.

But if we could have only one kind that would be much more attractive.
Adaptation looks like it is going to fail the KISS test.

 There was discussion as to how to get back to the original
 object from an adapter.  Is this in scope of PEP 246?

Seems too complex.  Again, KISS.

 Sticky adapters, that is, ones where there is only one instance
 per adaptee is a common use case.  Should the registry of PEP 246
 provide this feature?

Ditto.  If you really need this, __adapt__ and __conform__ could use a
cache.

-- 
--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] PEP 246, Feedback Request

2005-01-15 Thread Clark C. Evans
I started to edit the PEP, but found that we really don't have any
consensus on a great many items. The following is a bunch of topics,
and a proposed handling of those topics.  A bulk of this comes from
a phone chat I had with Alex this past afternoon, and other items
come from my understanding of the mailing list, or prior conversations
with Phillip, among others.  It's a strawman.

I'd really very much like feedback on each topic, preferably only
one post per person summarizing your position/suggestions.  I'd
rather not have a run-away discussion on this post.

---
-
  topic: a glossary
  overview:
It seems that we are having difficulty with words that have shifting
definitions.  The next PEP edit will need to add a glossary that 
nails down some meanings of these words.  Following are a few 
proposed terms/meanings.
  proposal:
  - protocol means any object, usually a type or class or interface,
which guides the construction of an adapter
  - adaptee is the object which is to be adapted, the original object
  - adaptee-class refers to the adaptee's class
  - adapter refers to the result of adapting an adaptee to a protocol
  - factory refers to a function, f(adaptee) - adapter, where 
the resulting adapter complies with a given protocol
  feedback:
Much help is needed here; either respond to this thread with
your words and definitions, or email them directly to Clark 
and he will use your feedback when creating the PEP's glossary.
-
  topic: a registry mechanism
  overview:
It has become very clear from the conversations the past few
days that a registry is absolutely needed for the kind of adapt()
behavior people are currently using in Zope, Twisted, and Peak.
  proposal:
  - The PEP will define a simple and flexible registry mechanism.
  - The registry will be a mapping from a (adaptee-class, protocol) 
pair to a corresponding factory.
  - Only one active registration per pair (see below)
  feedback:
We welcome/encourage experiences and concreate suggestions from
existing registries.  Our goal is to be minimal, extensible,
and sufficient.  See other topics for more specific concerns
before you comment on this more general topic.
-
  topic: should 'object' be impacted by PEP 246
  overview:
The semantics of exceptions depend if 'object' is given a
default __conform__ method (which would do isinstance), in which
case, returning None in a subclass could be used to prevent
Liskov violations. However, by requiring a change to 'object',
it may hinder adoption or slow-down testing.
  proposal:
  - We will not ask/require changes to `object'.
  - Liskov violations will be managed via the registry, see below.
  - This is probably faster for isinstance cases?
  feedback:
If you really think we should move isinstance() into
object.__conform__, then here is your chance to make a final
stand. ;)
-
  topic: adaption stages
  overview:
There are several stages for adaptation.  It was recommended
that the 'registry' be the first stop in the chain. 
  proposal:
  - First, the registry is checked for a suitable adapter
  - Second, isinstance() is checked, the adaptee is an instance
of the protocol, adaptation ends and adaptee is returned.
  - Third, __conform__ on the adaptee is called with the given
protocol being requested.
  - Fourth, __adapt__ on the protocol is called, with the given
adaptee.
  feedback:
This largely dependent upon the previous topic, but if something
isn't obvious (mod exceptions below), please say something.
-
  topic: module vs built-in
  overview:
Since we will be adding a registry, exceptions, and other items,
it probably makes sense to use a module for 'adapt'.
  proposal:
  - PEP 246 will ask for a `adapt' module, with an `adapt' function.
  - The registry will be contained in this module, 'adapt.register'
  - The `adapt' module can provide commonly-used adapter factories,
such as adapt.Identity.
  - With a standardized signature, frameworks can provide their own
'local' registry/adapt overrides.
  feedback:
Please discuss the merits of a module approach, and if having
local registries is important (or worth the added complexity).
Additional suggestions on how the module should be structured
are welcome. 
-
  topic: exception handling
  overview:
How should adaption stages progress and exceptions be handled.
There were problems with swallowed TypeError exceptions in 
the 2001 version of the PEP, type errors are not swallowed.
  proposal:
  - The 'adapt' module will define an adapt.AdaptError(TypeError).
  - At any stage of adaptation, if None is returned, the adaptation
continues to the next stage.
  - Any exception other than adapt.AdaptException(TypeError)
causes the adapt() call to fail, and the exception to be 
raised to the caller of adapt(); the 'default' value is not
returned in this case.
  - At 

Re: [Python-Dev] PEP 246, Feedback Request

2005-01-15 Thread Phillip J. Eby
At 11:04 PM 1/15/05 -0500, Clark C. Evans wrote:
  topic: a glossary
  overview:
It seems that we are having difficulty with words that have shifting
definitions.  The next PEP edit will need to add a glossary that
nails down some meanings of these words.  Following are a few
proposed terms/meanings.
It would also be helpful to distinguish between 1-to-1 as a adapters, and 
1-to-many view adapters.  There isn't a really good terminology for this, 
but it's important at least as it relates to type declarations.


  - Any exception other than adapt.AdaptException(TypeError)
causes the adapt() call to fail, and the exception to be
raised to the caller of adapt(); the 'default' value is not
returned in this case.
  - At any stage of adaption, if adapt.AdaptException(TypeError) is
raised, then the adaptation process stops, as if None had been
returned from each stage.
  - If all adaption stages return None, there are two cases.  If the
call to adapt() had a 'default' value, then this is returned;
otherwise, an adapt.AdaptException is raised.
-1; This allows unrelated AdaptExceptions to end up being silently 
caught.  These need to be two different exceptions if you want to support 
stages being able to veto adaptation.  Perhaps you should have a distinct 
VetoAdaptation error to support that use case.


  topic: transitivity
  ...
  proposal:
  ...
  feedback:
I'm looking for warts in this plan, and verification if
something like this has been done -- comments how well
it works.  Alternative approaches?
I'll try to think some more about this one later, but I didn't see any 
obvious problems at first glance.


  topic: declaration (aka Guido's syntax) and intrinsic adaption
  overview:
Guido would like his type declaration syntax (see blog entry) to
be equivalent to a call to adapt() without any additional
arguments.  However, not all adapters should be created in the
context of a declaration -- some should be created more
explicitly.  We propose a mechanism where an adapter factory can
register itself as not suitable for the declaration syntax.
It would be much safer to have the reverse be the default; i.e., it should 
take special action to declare an adapter as being *suitable* for use with 
type declarations.

IOW, sticky intrinsic adapters should be the default, and volatile 
accessories should take an extra action to make them usable with type 
declarations.


  feedback:
This is the simplest solution I heard on the list; the word
'intrinsic' was given by Alex.  Is there a better word?
Sadly, no.  I've been playing with words like extender, mask, 
personality etc. to try and find a name for a thing you only reasonably 
have one of, versus things you can have many of like accessory, add-on, 
etc.


  topic: adaptee (aka origin)
  overview:
There was discussion as to how to get back to the original
object from an adapter.  Is this in scope of PEP 246?
  proposal:
  - we specify an __adaptee__ property, to be optionally implemented
by an adapter that provides a reference adaptee
  - the adapt.register method has an optional argument, 'adaptee',
that defaults to False; if it is True, adapt() calls will stuff
away into a weak-reference mapping from adapter to adaptee.
  - an adapt.adaptee(adaptor) function which returns the given
adaptee for the adaptor; this first checks the weak-reference
table, and then checks for an __adaptee_
  feedback:
Is this useful, worth the complexity?
This is tied directly to intrinsicness and stickyness.  If you are 
intrinsic, you *must* have __adaptee__, so that adapt can re-adapt you 
safely.  If you are intrinsic, you *must* be stateless or 
sticky.  (Stateless can be considered an empty special case of 
sticky)  So, you might be able to combine a lot of these options to make 
the interface cleaner.

Think of it this way: if the adapter is intrinsic, it's just a 
personality of the underlying object.  So you don't want to re-adapt a 
personality, instead you re-adapt the original object.

But for a non-intrinsic adapter, the adapter is an independent object only 
incidentally related to the original adaptee, so it is now an original 
object of its own.


  topic: sticky
  overview:
Sticky adapters, that is, ones where there is only one instance
per adaptee is a common use case.  Should the registry of PEP 246
provide this feature?
Ideally, yes.

  proposal:
  - the adapt.register method has an optional argument, 'sticky',
that defaults to False
Make it default to whatever the 'intrinsic' setting is, because the only 
time you don't care for an intrinsic adapter is if the adapter is 
completely stateless.  Or, better yet, call it 'volatile' or something and 
default to False.  (I.e, you have to be say you're willing to have it 
volatile.)

If you get all of these features, it's going to come mighty close to the 
functionality I've written up in