Re: [Python-Dev] PEP 246: lossless and stateless
At 10:09 AM 1/14/05 +0100, Just van Rossum wrote:
Guido van Rossum wrote:
Are there real-life uses of stateful adapters that would be thrown out by this requirement?
Here are two interfaces we're using in a project:
http://just.letterror.com/ltrwiki/PenProtocol (aka "SegmentPen") http://just.letterror.com/ltrwiki/PointPen
They're both abstractions for drawing glyphs (characters from a font). Sometimes the former is more practical and sometimes the latter. We really need both interfaces. Yet they can't be adapted without keeping some state in the adapter.
Maybe I'm missing something, but for those interfaces, isn't it okay to keep the state in the *adapted* object here? In other words, if PointPen just added some private attributes to store the extra data?
Implicit adaptations may be dangerous here, but I'm not so sure I care. In my particular use case, it will be very rare that people want to do
funcTakingPointPen(segmentPen) otherFuncTakingPointPen(segmentPen)
But if the extra state were stored on the segmentPen rather than the adapter, this would work correctly, wouldn't it? Whereas with it stored in an adapter, it wouldn't.
Phillip J. Eby wrote:
At 10:09 AM 1/14/05 +0100, Just van Rossum wrote:
Guido van Rossum wrote:
Are there real-life uses of stateful adapters that would be thrown out by this requirement?
Here are two interfaces we're using in a project:
http://just.letterror.com/ltrwiki/PenProtocol (aka "SegmentPen") http://just.letterror.com/ltrwiki/PointPen
They're both abstractions for drawing glyphs (characters from a font). Sometimes the former is more practical and sometimes the latter. We really need both interfaces. Yet they can't be adapted without keeping some state in the adapter.
Maybe I'm missing something, but for those interfaces, isn't it okay to keep the state in the *adapted* object here? In other words, if PointPen just added some private attributes to store the extra data?
Implicit adaptations may be dangerous here, but I'm not so sure I care. In my particular use case, it will be very rare that people want to do
funcTakingPointPen(segmentPen) otherFuncTakingPointPen(segmentPen)
But if the extra state were stored on the segmentPen rather than the adapter, this would work correctly, wouldn't it? Whereas with it stored in an adapter, it wouldn't.
Are you saying the adapter could just hijack some attrs on the adapted object? Or ore you saying the adapted object should be aware of the adapter? Both don't sound right, so I hope I'm misunderstanding... Just
On Fri, 2005-01-14 at 10:07 -0500, Phillip J. Eby wrote:
Maybe I'm missing something, but for those interfaces, isn't it okay to keep the state in the *adapted* object here? In other words, if PointPen just added some private attributes to store the extra data?
I have been following this discussion with quite a lot of interest, and I have to confess that a lot of what's being discussed is confusing me. I use stateful adapters quite a bit - Twisted has long had a concept of "sticky" adapters (they are called "persistent" in Twisted, but I think I prefer "sticky"). Sometimes my persistent adapters are sticky, sometimes not. Just's example of iter() as an adaptation is a good example of a non-sticky stateful adaptation, but this example I found interesting, because it seems that the value-judgement of stateless adapters as "good" is distorting design practices to make other mistakes, just to remove state from adapters. I can't understand why PJE thinks - and why there seems to be a general consensus emerging - that stateless adapters are intrinsically better. For the sake of argument, let's say that SegmentPen is a C type, which does not have a __dict__, and that PointPen is a Python adapter for it, in a different project. Now, we have nowhere to hide PointPen's state on SegmentPen - and why were we trying to in the first place? It's a horrible breach of encapsulation. The whole *point* of adapters is to convert between *different* interfaces, not merely to rename methods on the same interface, or to add extra methods that work on the same data. To me, "different interfaces" means that the actual meaning of the operations is different - sometimes subtly, sometimes dramatically. There has to be enough information in one interface to get started on the implementation of another, but the fact that such information is necessary doesn't mean it is sufficient. It doesn't mean that there is enough information in the original object to provide a complete implementation of a different interface. If there were enough information, why not just implement all of your interfaces on the original class? In the case of our hypothetical cSegmentPen, we *already* have to modify the implementation of the original class to satisfy the needs of a "stateless" adapter. When you're modifying cSegmentPen, why not just add the methods that you wanted in the first place? Here's another example: I have a business logic class which lives in an object database, typically used for a web application. I convert this into a desktop application. Now, I want to adapt IBusinessThunk to IGtkUIPlug. In the process of doing so, I have to create a GTK widget, loaded out of some sort of resource file, and put it on the screen. I have to register event handlers which are associated with that adapter. The IBusinessThunk interface doesn't specify a __dict__ attribute as part of the interface, or the ability to set arbitrary attributes. And nor should it! It is stored in an indexed database where every attribute has to be declared, maybe, or perhaps it uses Pickle and sticking a GTK widget into its representation would make it un-pickleable. Maybe it's using an O/R mapper which loses state that is not explicitly declared or explicitly touch()ed. There are a variety of problems which using it in this unsupported way might create, but as the implementor of a IGtkUIPlug, I should be concerned *only* with what IBusinessThunk provides, which is .embezzle() and .checkFundsAvailable(). I am not writing an adapter from DBBusinessThunkImpl, after all, and perhaps I am receiving a test implementation that works entirely differently. This example gets to the heart of what makes interfaces useful to me - model/view separation. Although one might be hard pressed to call some of the things I use adaptation for "views", the idea of mediated access from a user, or from network protocol, or from some internal code acting on behalf of a user is the overwhelming majority of my use-cases. Most of the other use-cases I can think of are like the one James mentions, where we really are using adaptation to shuffle around some method names and provide simple glossing over totally isomorphic functionality to provide backwards (or sideways, in the case of almost-identical libraries provided on different platforms or environments) compatibility. For these reasons I would vastly prefer it if transitivity were declared as a property of the *adaptation*, not of the adapter or the registry or to be inferred from various vaguely-defined properties like "losslessness" or "statelessness". I am also concerned about any proposal which introduces transitivity-based errors at adaptation time rather than at registration time, because by then it is definitely too late to do anything about it. I wish I had a better suggestion, but I'm still struggling through the rest of the thread :).
On Jan 14, 2005, at 19:02, Glyph Lefkowitz wrote:
On Fri, 2005-01-14 at 10:07 -0500, Phillip J. Eby wrote:
Maybe I'm missing something, but for those interfaces, isn't it okay to keep the state in the *adapted* object here? In other words, if PointPen just added some private attributes to store the extra data?
Here's another example: I have a business logic class which lives in an object database, typically used for a web application. I convert this into a desktop application. Now, I want to adapt IBusinessThunk to IGtkUIPlug. In the process of doing so, I have to create a GTK widget, loaded out of some sort of resource file, and put it on the screen. I have to register event handlers which are associated with that adapter.
The IBusinessThunk interface doesn't specify a __dict__ attribute as part of the interface, or the ability to set arbitrary attributes. And nor should it! It is stored in an indexed database where every attribute has to be declared, maybe, or perhaps it uses Pickle and sticking a GTK widget into its representation would make it un-pickleable. Maybe it's using an O/R mapper which loses state that is not explicitly declared or explicitly touch()ed. There are a variety of problems which using it in this unsupported way might create, but as the implementor of a IGtkUIPlug, I should be concerned *only* with what IBusinessThunk provides, which is .embezzle() and .checkFundsAvailable(). I am not writing an adapter from DBBusinessThunkImpl, after all, and perhaps I am receiving a test implementation that works entirely differently.
This example gets to the heart of what makes interfaces useful to me - model/view separation. Although one might be hard pressed to call some of the things I use adaptation for "views", the idea of mediated access from a user, or from network protocol, or from some internal code acting on behalf of a user is the overwhelming majority of my use-cases.
I think the idea is that it's "better" to have an adapter from IBusinessThunk -> IGtkUIPlugFactory, which you can use to *create* a stateful object that complies with the IGtkUIPlug interface. This way, you are explicitly creating something entirely new (derived from something else) with its own lifecycle and state and it should be managed accordingly. This is clearly not simply putting a shell around an IBusinessThunk that says "act like this right now". -bob
On Fri, 2005-01-14 at 19:14 -0500, Bob Ippolito wrote:
I think the idea is that it's "better" to have an adapter from IBusinessThunk -> IGtkUIPlugFactory, which you can use to *create* a stateful object that complies with the IGtkUIPlug interface.
This way, you are explicitly creating something entirely new (derived from something else) with its own lifecycle and state and it should be managed accordingly. This is clearly not simply putting a shell around an IBusinessThunk that says "act like this right now".
Yes. This is exactly what I meant to say. Maybe there are 2 entirely different use-cases for adaptation, and we shouldn't be trying to confuse the two, or conflate them into one system? I am going to go have a look at PEAK next, to see why there are so many stateless adapters there.
On Fri, 14 Jan 2005 19:02:52 -0500, Glyph Lefkowitz
On Fri, 2005-01-14 at 10:07 -0500, Phillip J. Eby wrote:
Maybe I'm missing something, but for those interfaces, isn't it okay to keep the state in the *adapted* object here? In other words, if PointPen just added some private attributes to store the extra data?
I have been following this discussion with quite a lot of interest, and I have to confess that a lot of what's being discussed is confusing me. I use stateful adapters quite a bit - Twisted has long had a concept of "sticky" adapters (they are called "persistent" in Twisted, but I think I prefer "sticky"). Sometimes my persistent adapters are sticky, sometimes not. Just's example of iter() as an adaptation is a good example of a non-sticky stateful adaptation, but this example I found interesting, because it seems that the value-judgement of stateless adapters as "good" is distorting design practices to make other mistakes, just to remove state from adapters. I can't understand why PJE thinks - and why there seems to be a general consensus emerging - that stateless adapters are intrinsically better.
My feeling here was not that people thought that stateless adapters were in general intrinsically better -- just when the adaptation was going to be done implicitly (e.g. by type declarations). When no state is involved, adapting an object multiple times can be guaranteed to produce the same adapted object, so if this happens implicitly, it's not a big deal. When state is involved, _some_ decisions have to be made, and it seems like those decisions should be made explicitly... Steve -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy
At 05:37 PM 1/14/05 -0700, Steven Bethard wrote:
On Fri, 14 Jan 2005 19:02:52 -0500, Glyph Lefkowitz
wrote: On Fri, 2005-01-14 at 10:07 -0500, Phillip J. Eby wrote:
Maybe I'm missing something, but for those interfaces, isn't it okay to keep the state in the *adapted* object here? In other words, if PointPen just added some private attributes to store the extra data?
I have been following this discussion with quite a lot of interest, and I have to confess that a lot of what's being discussed is confusing me. I use stateful adapters quite a bit - Twisted has long had a concept of "sticky" adapters (they are called "persistent" in Twisted, but I think I prefer "sticky"). Sometimes my persistent adapters are sticky, sometimes not. Just's example of iter() as an adaptation is a good example of a non-sticky stateful adaptation, but this example I found interesting, because it seems that the value-judgement of stateless adapters as "good" is distorting design practices to make other mistakes, just to remove state from adapters. I can't understand why PJE thinks - and why there seems to be a general consensus emerging - that stateless adapters are intrinsically better.
My feeling here was not that people thought that stateless adapters were in general intrinsically better -- just when the adaptation was going to be done implicitly (e.g. by type declarations).
Yes, exactly. :)
When no state is involved, adapting an object multiple times can be guaranteed to produce the same adapted object, so if this happens implicitly, it's not a big deal. When state is involved, _some_ decisions have to be made, and it seems like those decisions should be made explicitly...
At last someone has been able to produce a concise summary of my insane ramblings. :) Yes, this is precisely the key: implicit adaptation should always return an adapter with the "same" state (for some sensible meaning of "same"), because otherwise control of an important aspect of the system's behavior is too widely distributed to be able to easily tell for sure what's going on. It also produces the side-effect issue of possibly introducing transitive adaptation, and again, that property is widely distributed and hard to "see". Explicit adaptation to add per-adapter state is just fine; it's only *implicit* "non-sticky stateful" adaptation that creates issues. Thus, the PEP I'm working on focuses on making it super-easy to make stateless and sticky stateful adapters with a bare minimum of declarations and interfaces and such.
On Fri, 14 Jan 2005 20:06:22 -0500, Phillip J. Eby
My feeling here was not that people thought that stateless adapters were in general intrinsically better -- just when the adaptation was going to be done implicitly (e.g. by type declarations).
Yes, exactly. :)
In which case, given that there is no concept in PEP 246 of implicit adaptation, can we please make a clear separation of this discussion from PEP 246? (The current version of the PEP makes no mention of transitive adaptation, as optional or required behaviour, which is the only other example of implicit adaptation I can think of). I think there are the following distinct threads of discussion going on at the moment: * Details of what should be in PEP 246 * Discussions spinning off from Guido's type-declaration-as-adaptation proposal * Discussion of what counts as a "good" adapter * Philip's new generic function / ducy typing proposals Is that even close to others' understanding? Just trying to keep my brain from exploding :-) Paul.
At 01:20 PM 1/15/05 +0000, Paul Moore wrote:
I think there are the following distinct threads of discussion going on at the moment:
* Details of what should be in PEP 246 * Discussions spinning off from Guido's type-declaration-as-adaptation proposal
My understanding was that the first needed to be considered in context of the second, since it was the second which gave an implicit blessing to the first. PEP 246 had languished in relative obscurity for a long time until Guido's blessing it for type declarations brought it back into the spotlight. So, I thought it important to frame its discussion in terms of its use for type declaration.
* Discussion of what counts as a "good" adapter
Alex was originally trying to add to PEP 246 some recommendations regarding "good" vs. "bad" adaptation, so this is actually part of "what should be in PEP 246"
* Philip's new generic function / ducy typing proposals
And of course this one is an attempt to unify everything and replace PEP 245 (not 246) with a hopefully more pythonic way of defining interfaces and adapters. I hope to define a "relatively safe" subset of PEP 246 for type declarations that can be done automatically by Python, in a way that's also conceptually compatible with COM and Java casting (possibly making Jython and IronPython's lives a little easier re: type declarations).
At 07:02 PM 1/14/05 -0500, Glyph Lefkowitz wrote:
For the sake of argument, let's say that SegmentPen is a C type, which does not have a __dict__, and that PointPen is a Python adapter for it, in a different project.
There are multiple implementation alternatives possible here; it isn't necessary that the state be hidden there. The point is that, given the same SegmentPen, we want to get the same PointPen each time we *implicitly* adapt, in order to avoid violating the "naive" developer's mental model of what adaptation is -- i.e. an extension of the object's state, not a new object with independent state. One possible alternative implementation is to use a dictionary from object id to a 'weakref(ob),state' tuple, with the weakref set up to remove the entry when 'ob' goes away. Adapters would then have a pointer to their state object and a pointer to the adaptee. As long as an adapter lives, the adaptee lives, so the state remains valid. Or, if no adapters remain, but the adaptee still lives, then so does the state which can be resurrected when a new adapter is requested. It's too bad Python doesn't have some sort of deallocation hook you could use to get notified when an object goes away. Oh well. Anyway, as you and I have both pointed out, sticky adaptation is an important use case; when you need it, you really need it.
This example gets to the heart of what makes interfaces useful to me - model/view separation. Although one might be hard pressed to call some of the things I use adaptation for "views", the idea of mediated access from a user, or from network protocol, or from some internal code acting on behalf of a user is the overwhelming majority of my use-cases.
If every time you pass a "model" to something that expects a "view", you get a new "view" instance being created, things are going to get mighty confusing, mighty fast. In contrast, explicit adaptation with 'adapt(model,IView)' or 'IView(model)' allows you to explicitly control the lifecycle of the view (or views!) you want to create. Guido currently thinks that type declaration should be implemented as 'adapt(model,IView)'; I think that maybe it should be restricted (if only by considerations of "good style") to adapters that are sticky or stateless, reserving per-state adaptation for explicit creation via today's 'adapt()' or 'IFoo(ob)' APIs.
I wish I had a better suggestion, but I'm still struggling through the rest of the thread :).
I'll be starting work on the PEP soon, maybe I'll have a rough draft of at least the first few sections ready to post tonight so everybody can get started on ripping them to pieces. The sooner I know about the holes, the sooner I can fix 'em. Or alternatively, the sooner Guido shoots it down, the less work I have to do on the PEP. :)
On 2005 Jan 15, at 02:30, Phillip J. Eby wrote:
is requested. It's too bad Python doesn't have some sort of deallocation hook you could use to get notified when an object goes away. Oh well.
For weakly referenceable objects, it does. Giving one to other objects would be almost isomorphic to making every object weakly referenceable, wouldn't it? Or am I missing something...? Alex
At 10:35 AM 1/15/05 +0100, Alex Martelli wrote:
On 2005 Jan 15, at 02:30, Phillip J. Eby wrote:
is requested. It's too bad Python doesn't have some sort of deallocation hook you could use to get notified when an object goes away. Oh well.
For weakly referenceable objects, it does. Giving one to other objects would be almost isomorphic to making every object weakly referenceable, wouldn't it? Or am I missing something...?
I meant if there was some way to listen for a particular object's allocation, like sticking all the pointers you were interested in into a big dictionary with callbacks and having a callback run whenever an object's refcount reaches zero. It's doubtless completely impractical, however. I think we can probably live with only weak-referenceable objects being seamlessly sticky, if that's a word. :) Actually, I've just gotten to the part of the PEP where I have to deal with stateful adapters and state retention, and I think I'm going to use this terminology for the three kinds of adapters: * operations (no adapter class needed) * extenders (operations + a consistent state that conceptually adds state to the base object rather than creating an object w/separate lifetime) * "volatile", "inconsistent", or "disposable" adapters (state may be lost or multiplied if passed to different routines) The idea is to make it really easy to make any of these, but for the last category you should have to explicitly declare that you *want* volatility (or at least that you are willing to accept it, if the target type is not weak-referenceable). In this way, all three kinds of adaptation may be allowed, but it takes one extra step to create a potentially "bad" adapter. Right now, people often create volatile adapters even if what they want is an extender ("sticky adapter"), because it's more work to make a functioning extender, not because they actually want volatility. So, let's reverse that and make it easier to create extenders than it is to create volatile adapters. And, since in some cases an extender won't be possible even when it's what you want, we could go ahead and allow type declarations to make them, as long as the creator has specified that they're volatile. Meanwhile, all three kinds of adapters should avoid accidental implicit transitivity by only adapting the "original object". (Unless, again, there is some explicit choice to do otherwise.) This makes the type declaration system a straightforward extension of the COM QueryInterface and Java casting models, where an object's "true identity" is always preserved regardless of which interface you access its operations through.
Phillip J. Eby wrote:
At 07:02 PM 1/14/05 -0500, Glyph Lefkowitz wrote:
For the sake of argument, let's say that SegmentPen is a C type, which does not have a __dict__, and that PointPen is a Python adapter for it, in a different project.
There are multiple implementation alternatives possible here; it isn't necessary that the state be hidden there. The point is that, given the same SegmentPen, we want to get the same PointPen each time we *implicitly* adapt, in order to avoid violating the "naive" developer's mental model of what adaptation is -- i.e. an extension of the object's state, not a new object with independent state.
One possible alternative implementation is to use a dictionary from object id to a 'weakref(ob),state' tuple, with the weakref set up to remove the entry when 'ob' goes away. Adapters would then have a pointer to their state object and a pointer to the adaptee. As long as an adapter lives, the adaptee lives, so the state remains valid. Or, if no adapters remain, but the adaptee still lives, then so does the state which can be resurrected when a new adapter is requested. It's too bad Python doesn't have some sort of deallocation hook you could use to get notified when an object goes away. Oh well.
That sounds extremely complicated as apposed to just storing the sate where it most logically belongs: on the adapter. And all that to work around a problem that I'm not convinced needs solving or even exists. At the very least *I* don't care about it in my use case.
Anyway, as you and I have both pointed out, sticky adaptation is an important use case; when you need it, you really need it.
Maybe I missed it, but was there an example posted of when "sticky adaptation" is needed? It's not at all clear to me that "sticky" behavior is the best default behavior, even with implicit adoptation. Would anyone in their right mind expect the following to return [0, 1, 2, 3, 4, 5] instead of [0, 1, 2, 0, 1, 2]?
from itertools import * seq = range(10) list(chain(islice(seq, 3), islice(seq, 3))) [0, 1, 2, 0, 1, 2]
Just
On 2005 Jan 15, at 01:02, Glyph Lefkowitz wrote: ...
Now, we have nowhere to hide PointPen's state on SegmentPen - and why were we trying to in the first place? It's a horrible breach of encapsulation. The whole *point* of adapters is to convert between *different* interfaces, not merely to rename methods on the same interface, or to add extra methods that work on the same data. To me,
A common implementation technique, when you'd love to associate some extra data to an object, but can't rely on the object having a __dict__ to let you do that conveniently, is to have an auxiliary dict of bunches of extra data, keyed by object's id(). It's a bit messier, in that you have to deal with cleanup issues when the object goes away, as well as suffer an extra indirectness; but in many use cases it's quite workable. I don't see doing something like myauxdict[id(obj)] = {'foo': 'bar'} as "terribly invasive", and therefore neither do I see obj.myauxfoo = 'bar' as any more invasive -- just two implementation techniques for the same task with somewhat different tradeoffs. The task, associating extra data with obj without changing obj type's source, won't just go away. Incidentally, the realization of this equivalence was a key step in my very early acceptance of Python. In the first few days, the concept "some external code might add an attribute to obj -- encapsulation breach!" made me wary; then CLICK, the first time I had to associate extra data to an object and realized the alleged ``breach'' was just a handy implementation help for the task I needed anyway, I started feeling much better about it. Adapter use cases exist for all three structures: 1. the adapter just needs to change method names and signatures or combine existing methods of the object, no state additions; 2. the adapter needs to add some per-object state, which must be shared among different adapters which may simultaneously exist on the same object; 3. the adapter needs to add some per-adapter state, which must be distinct among different adapters which may simultaneously exist on the same object. Case [1] is simplest because you don't have to wonder whether [2] or [3] are better, which may be why it's being thought of as "best". Case [3] may be dubious when we talk about AUTOMATIC adaptation, because in [3] making and using two separate adapters has very different semantics from making just one adapter and using it twice. When you build the adapter explicitly of course you have full control and hopefully awareness of that. For example, in Model/View, clearly you want multiple views on the same model and each view may well need a few presentation data of its own; if you think of it as adaptation, it's definitely a [3]. But do we really want _automatic_ adaptation -- passing a Model to a function which expects a View, and having some kind of default presentation data be used to make a default view on it? That, I guess, is the dubious part.
"different interfaces" means that the actual meaning of the operations is different - sometimes subtly, sometimes dramatically. There has to be enough information in one interface to get started on the implementation of another, but the fact that such information is necessary doesn't mean it is sufficient. It doesn't mean that there is enough information in the original object to provide a complete implementation of a different interface.
If there were enough information, why not just implement all of your interfaces on the original class? In the case of our hypothetical cSegmentPen, we *already* have to modify the implementation of the original class to satisfy the needs of a "stateless" adapter. When you're modifying cSegmentPen, why not just add the methods that you wanted in the first place?
Reason #1: because the author of the cSegmentPen code cannot assume he or she knows about all the interfaces to which a cSegmentPen might be adapted a la [3]. If he or she provides a __dict__, or makes cSegmentPen weakly referenceable, all [3]-like adaptation needs are covered at one (heh heh) stroke.
Here's another example: I have a business logic class which lives in an object database, typically used for a web application. I convert this into a desktop application. Now, I want to adapt IBusinessThunk to IGtkUIPlug. In the process of doing so, I have to create a GTK widget, loaded out of some sort of resource file, and put it on the screen. I have to register event handlers which are associated with that adapter.
OK, a typical case of model/view and thus a [3]. The issue is whether you want adaptation to be automatic or explicit, in such cases.
Most of the other use-cases I can think of are like the one James mentions, where we really are using adaptation to shuffle around some method names and provide simple glossing over totally isomorphic functionality to provide backwards (or sideways, in the case of almost-identical libraries provided on different platforms or environments) compatibility.
And what's wrong with that? Those are the "case [1]" adapters, and they're very useful. I guess this boils down to the issue that you don't think there are use cases for [2], where the extra state is needed but it had better be per-object, shared among adapters, and not per-adapter, distinct for each adapter. Well, one example in the model/view area comes from 3d modeling for mechanical engineering: the model is a complex collection of solids which only deal with geometrical properties, the views are "cameras" rendering scenes onto windows on the screen. Each view has some modest state of its own (camera distance, angles, screen coordinates), but also there are some presentation data -- alien to the model itself, which only has geometry -- which are required to be shared among views, such as lighting information and surface texturing. One approach would be to first wrap the bare-model into an enriched-model, once only; and adapt only the enriched model to the views. If it's important to have different sets of views of the same geometry with different lighting &c, it's the only way to go; but sometimes the functional requirement is exactly the reverse -- ensure there is never any discrepancy among the lighting, texturing etc of the views over the same (geometrical) model. Nothing particularly wrong, then, in having the bunch of information that is the "enriched model" (lighting &c) be known only to the views but directly associated with the geometry-model.
For these reasons I would vastly prefer it if transitivity were declared as a property of the *adaptation*, not of the adapter or the registry or to be inferred from various vaguely-defined properties like "losslessness" or "statelessness". I am also concerned about any proposal which introduces transitivity-based errors at adaptation time rather than at registration time, because by then it is definitely too late to do anything about it.
Fair enough, but for Guido's suggested syntax of "def f(X:Y):..." meaning X=adapt(X,Y) at function entry, the issue is how that particular "default/implicit" adaptation should behave -- is it always allowed to be transitive, never, only when Y is an interface and not a class, or under what specific set of constraints? Alex
participants (7)
-
Alex Martelli
-
Bob Ippolito
-
Glyph Lefkowitz
-
Just van Rossum
-
Paul Moore
-
Phillip J. Eby
-
Steven Bethard