[Python-Dev] PEP 246, Feedback Request (original) (raw)
Clark C. Evans cce at clarkevans.com
Sun Jan 16 05:04:24 CET 2005
- Previous message: [Python-Dev] PEP 246, redux
- Next message: [Python-Dev] PEP 246, Feedback Request
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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.
- PEP 246 will ask for a
- 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 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. feedback: I think this is the same as the current PEP, and different from the first PEP. Comments? Anything that was missed?
- topic: transitivity
overview:
A case for allowing A->C to work when A->B and B->C is
available; an equally compelling case to forbid this was also
given. There are numerous reasons for not allowing transitive
adapters, mostly that 'lossy' adapters or 'stateful' adapters
are usually the problem cases. However, a hard-and-fast rule
for knowing when transitivity exists wasn't found.
proposal:
- When registering an adapter factory, from A->B, an additional flag 'transitive' will be available.
- This flag defaults to False, so specific care is needed when registering adapters which one considers to be transitive.
- If there exist two adapter factories, X: A->B, and Y: B->C, the path factory Z: A->C will be considered registered if and only if both X and Y were registered 'Transitive'.
- It is an error for a registration to cause two path factories from A to C to be constructed; thus the registry will never have a case where two transitive adaptation paths exist at a single time.
- An explicit registration always has precedent over an a transitive path.
- 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. 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?
- topic: substitutability
overview:
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.
proposal:
- The 'adapt' module will define a 'LiskovAdaptionError', which has as a text description something like: "Although the given class '%s' derives from '%s', it has been marked as not being substitutable; although it is a subclass, the intent has changed so that one should not assume an 'is-a' relationship." % (adaptee.class, protocol)
- The 'adapt' module will provide an 'NotSubstitutable' adaption factory, which, by default, raises LiskovAdaptionError.
- If someone is concerned that their subclass should not be adapted to the superclass automatically, they should register the NotSubstitutable adapter to the superclass, recursively. feedback: I'm not sure how this would work for the adaptee-class's grandparent; perhaps a helper function that recursively marks super classes is needed? Other comments?
- 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.
proposal:
- The adapt.register method has an optional argument, 'intrinsic', that defaults to True.
- The adapt() function has an optional argument, 'intrinsic_only' which defaults to True; and thus is the default for the declaration syntax.
- If an adapter factory is registered with intrinsic = False, then it is not used by default calls to adapt().
- adapt( , intrinsic_only = False) will enable both sorts of adapters, intrinsic or not; enabling the use of adapters which should not be used by default in a declaration syntax.
- all adapters created through conform and adapt are by default intrinsic since this parameter is not part of the function signature feedback: This is the simplest solution I heard on the list; the word 'intrinsic' was given by Alex. Is there a better word? Should we even worry about this case? Any other ways to view this issue?
- 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?
- 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?
proposal:
- the adapt.register method has an optional argument, 'sticky', that defaults to False
- if the given adapter factory is marked sticky, then a call to adapt() will first check to see if a given adapter (keyed by protocol) has been created for the adaptee; if so, then that adapter is returned, otherwise the factory is asked to produce an adapter and that adapter is cashed. feedback: Is this useful, worth the complexity? It seems like an easy operation. The advantage to this approach (over each factory inheriting from a StickyFactory) is that registry queries can be done, to list sticky adapters and other bookkeeping chores.
Ok. That's it.
Cheers,
Clark
Clark C. Evans Prometheus Research, LLC. http://www.prometheusresearch.com/ o office: +1.203.777.2550 ~/ , mobile: +1.203.444.0557 // (( Prometheus Research: Transforming Data Into Knowledge \ , / - Research Exchange Database /\ - Survey & Assessment Technologies ` \ - Software Tools for Researchers ~ *
- Previous message: [Python-Dev] PEP 246, redux
- Next message: [Python-Dev] PEP 246, Feedback Request
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]