Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Hey, A few points instead of a point by point reply. * I thought we had agreed to add methods to Interface that support multi adapter and utility lookup. We seem to have, but only about the external API, not about where the implementation is. (even if in my plugin proposal the implementation still lies in zope.component) * Apparently not even single adapter lookup is supported by you, at least as implemented in zope.interface. I had not previously realized that the current implementation of __call__ could be considered wrong by you. * You appear to be looking for something that at least in the Python language is only accepted as a kind of hack: an ability to extend the API of an existing class far away from the definition of that class, without there being a subclassing relationship (or I suppose, a class decorator). The idea in Python is generally that the API of a class is defined by that class or its base classes, not elsewhere. * There is of course a way to extend what one can do with an object in Python. Subclassing is one way, adaptation another, and defining functions another. The last is what zope.component does. * I do not know of a user community that uses zope.interface and does not use a component architecture. The Twisted community for instance uses zope.interface's adapter registry and __call__ hook. This is an argument for making component lookup an integral part of zope.interface's responsibilities. I think you could even make an argument for folding zope.component's responsibilities into zope.interface, though I'm not currently proposing this (also because we're are looking to improve the implementation, see below). Generalizing what kinds of component lookups one can do using Interface seems like a good idea from this perspective. * I think it is entirely possible that people will plug in alternative component lookup strategies to zope.interface in the future, as the long discussion also involved changing the way zope.component's internals worked. * All this questioning of fundamentals makes me inclined to give up on this project for the time being. I thought we had reached a conclusion, but I was wrong. Too many cooks? Some more technical points: * you wonder about a 'context' parameter. Are you talking about the lookup context here? We hadn't considered passing through the lookup context in previous discussions. We could leave that out for the time being. * A single plugin seems fine instead of a list of plugin points for zope.interface. I think a single plugin, using a global would be the most straightforward and readable solution, but perhaps some performance measurements would be interesting. Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Thomas Lotze wrote: Chris McDonough wrote: Thomas Lotze wrote: Because then, if you use third-party code that uses zope.interface.Interface and other code (third-party or your own) that uses the subclassed interfaces, you'll have to deal with both types at the same time in your client code. You could use the new API on some interfaces but not on others, possibly on the same line of code. How readable or maintainable would such code be? I'm not sure, but if we had it to do all over again, this would be an obvious solution. It would be the work of maybe two days to convert all ZTK packages to use a z.c.interface.Interface, and any existing package would need to be touched anyway to use .adapt and .utility. So it bears some weight I think, even if it is eventually rejected. It does certainly bear some weight as one possibility to be considered. However, my point wasn't so much about converting a limited existing amount of code; you're obviously right about having to touch that anyway in order to use the new methods. My objection is this: If we go to the trouble of implementing basic interfaces in zope.interface plus derived ones with component lookup capabilities in zope.component and keep both around for their respective reasons of existence, then it is expected that there will be code that uses both types of interfaces for these very reasons (and maybe other types which have other added behaviour). Such code would become a lot less maintainable since you'd never know whether a given interface has a particular method just because the one next to it does. OTOH, registering all behaviour an application needs onto the same interface type doesn't create that problem. As long as you're familiar with the application at large, you will know for every interface that occurs in it which methods is has, how they need to be called and what their semantics are. Also, subclassing for adding behaviour introduces the typical problems of hierarchies and tight coupling. This isn't a practical problem as long as we only ever talk about adaptation as the only use of interfaces, but I'm trying to discuss interfaces as a language feature with a greater set of possible use cases. Maybe a hook or API extension just isn't the right thing here. Maybe we just give up on the idea that z.component worldview doesn't belong in z.interface, for the sake of implementation simplicity. - Move the Components class from zope.component.registry to zope.interface.adapter and leave behind an import alias. - Move the base registry from zope.component.globalregistry into zope.interface.adapter and leave behind an import alias. - Move the getSiteManager function from zope.component._api into zope.interface.adapter and leave behind an import alias. - Move the hookable implementation from zope.component.hookable into zope.interface.hookable and leave behind an import alias. - Change the zope.interface.interface.InterfaceClass implementation directly, adding adapts and utility methods, which would use zope.interface.adapter.getSiteManager to find the registry. z.interface would then become responsible for: - Providing an implementation of a component registry which has a z.c worldview: adapters and utilities, stolen from z.c.registry.Components. - Providing a function that returns the current component registry (getSiteManager, which will continue to be hookable; although maybe we should take the opportunity to rename it to actually mean something). - Providing the instance that is the default component registry. All other responsibility (global API functions, a persistent registry implementation, security stuff, zcml support, etc), would remain in z.component. This would also line up conceptually with usage of the ZCA by BFG, which does not hook getSiteManager by default, but still uses a ZCA component registry. - C ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Chris McDonough wrote: Thomas Lotze wrote: Chris McDonough wrote: Thomas Lotze wrote: Because then, if you use third-party code that uses zope.interface.Interface and other code (third-party or your own) that uses the subclassed interfaces, you'll have to deal with both types at the same time in your client code. You could use the new API on some interfaces but not on others, possibly on the same line of code. How readable or maintainable would such code be? I'm not sure, but if we had it to do all over again, this would be an obvious solution. It would be the work of maybe two days to convert all ZTK packages to use a z.c.interface.Interface, and any existing package would need to be touched anyway to use .adapt and .utility. So it bears some weight I think, even if it is eventually rejected. It does certainly bear some weight as one possibility to be considered. However, my point wasn't so much about converting a limited existing amount of code; you're obviously right about having to touch that anyway in order to use the new methods. My objection is this: If we go to the trouble of implementing basic interfaces in zope.interface plus derived ones with component lookup capabilities in zope.component and keep both around for their respective reasons of existence, then it is expected that there will be code that uses both types of interfaces for these very reasons (and maybe other types which have other added behaviour). Such code would become a lot less maintainable since you'd never know whether a given interface has a particular method just because the one next to it does. OTOH, registering all behaviour an application needs onto the same interface type doesn't create that problem. As long as you're familiar with the application at large, you will know for every interface that occurs in it which methods is has, how they need to be called and what their semantics are. Also, subclassing for adding behaviour introduces the typical problems of hierarchies and tight coupling. This isn't a practical problem as long as we only ever talk about adaptation as the only use of interfaces, but I'm trying to discuss interfaces as a language feature with a greater set of possible use cases. Maybe a hook or API extension just isn't the right thing here. Maybe we just give up on the idea that z.component worldview doesn't belong in z.interface, for the sake of implementation simplicity. - Move the Components class from zope.component.registry to zope.interface.adapter and leave behind an import alias. - Move the base registry from zope.component.globalregistry into zope.interface.adapter and leave behind an import alias. - Move the getSiteManager function from zope.component._api into zope.interface.adapter and leave behind an import alias. - Move the hookable implementation from zope.component.hookable into zope.interface.hookable and leave behind an import alias. - Change the zope.interface.interface.InterfaceClass implementation directly, adding adapts and utility methods, which would use zope.interface.adapter.getSiteManager to find the registry. z.interface would then become responsible for: - Providing an implementation of a component registry which has a z.c worldview: adapters and utilities, stolen from z.c.registry.Components. - Providing a function that returns the current component registry (getSiteManager, which will continue to be hookable; although maybe we should take the opportunity to rename it to actually mean something). - Providing the instance that is the default component registry. All other responsibility (global API functions, a persistent registry implementation, security stuff, zcml support, etc), would remain in z.component. This would also line up conceptually with usage of the ZCA by BFG, which does not hook getSiteManager by default, but still uses a ZCA component registry. - C OK, I just tried this. It's maybe 2 days worth of effort to untangle this as it also effectively means: - Moving the majority of interfaces and exceptions from zope.component.interfaces to zope.interface.interfaces - Folding zope.event into zope.interface (this turns out to make sense when you're down the rabbit hole some of the way). - Untangling the tests. I thought maybe it might be a bit easier (I thought maybe I could get it done today) so I'm going to give up the idea of doing it on spec without some positive feedback about the idea. - C ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Hey, Chris McDonough wrote: [snip experiment folding zope.component bits into zope.interface] I thought maybe it might be a bit easier (I thought maybe I could get it done today) so I'm going to give up the idea of doing it on spec without some positive feedback about the idea. Thanks for trying this! I do think it's an interesting direction to explore. We really need to involve Gary into this, though, to see whether it fits his thoughts. I've cc-ed him on this so he knows to look in this thread again. Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Hi, this is a long message with a lot of replies to things that I don't agree with. Since I realize that making those points over and over again doesn't get us anywhere, I'd like to point out first that I'm going to implement Martijn's suggestions anyway on one of my branches, hoping that seeing more actual code to talk about might help getting to more consensus. Martijn Faassen wrote: * It'd be nice if __call__ came back with a LookupError instead of a TypeError, but how to get from A to B without breakage? It's not possible without breakage. Unless we create a zope.interface specific LookupError which subclasses both the built-in LookupError and TypeError. zope.component's ComponentLookupError should subclass this special LookupError then. Technically true, so my statement was admittedly too strong. I just don't feel comfortable with the idea, which may well be just because it's the let's make both exceptions work sowmehow solution to me instead of the clear change I thought we were considering. OTOH, it's not that big an issue either, so I guess I'd be fine with it. * the methods can be on zope.interface even if zope.component isn't installed. They will behave as if the component registry is empty. This isn't covered by the consensus you mentioned above as far as I'm concerned. Yeah, I put that in so we can reach consensus on it. I thought Tres had a good idea going on there that makes the plugin behavior a lot cleaner. Hm, I can't help feeling pushed into this. While this plugin stuff is indeed nice *assuming* that we want all the zope.component concepts in zope.interface, it doesn't contribute to the decision about *whether* we want that in the first place. IFoo.adapt(context) raises LookupError, unless the context provides IFoo, in which case it returns context. IFoo.adapt(context, default=default) returns default unless context provides IFoo, in which case it returns context. IFoo.utility() raises LookupError. IFoo.utility(default=default) returns default I think looking at that API explains why we have trouble with having stub methods defined by zope.interface: these methods contain enough information about component concepts to blur the distinction between zope.interface and zope.component, but they still lie about the actual method signature. I don't understand you: why do you say they lie about their method signature? They should have the same signature and have a well-defined behavior if zope.component is not installed: there is nothing registered at all. zope.interface provides a plugin point that allows one to plug lookup behavior into it. When I wrote that, I was assuming that we were talking about patching interfaces with methods that have zope.component's full lookup semantics, including `name` and `context` parameters - which abviously would change the signatures. If we're talking about something that doesn't add those parameters, there's no lie involved but I don't see how our lookup methods could then access the full feature set of zope.component's lookups. In that case, I want the real contract to be in zope.interface. That's where the methods are, after all. We need to talk about the concept of an adapter and a utility briefly in zope.interface and defer to zope.component as the most common implementation. We already have this kind of behavior going on anyway with __call__() (even though not documented!). Well, we obviously disagree completely about this. The existing __call__ method is neither a good example of a zope.component lookup API, nor do I think that it was fortunate to wire up the adaptation concept in zope.interface through __call__ in the first place. I'd rather try to loosen this reference to component concepts than use it as a reason for adding more. You'll have to go into more detail. Why does it feel wrong to you? Because it is just another way of encoding the zope.component details within zope.interface. I would love to add a plugin API that is generic enough to apply equally to other uses of interfaces than component lookup, and that would allow implementations of component lookup with different concepts and different lookup methods than those of zope.component. Why is it a problem that the zope.interface package gains knowledge about adaptation (which it always had, anyway) (and which, IMO, it shouldn't have in the first place) and utility lookup? Because if we're serious about making interfaces more of a language feature, they should at their core be reduced to *being* mostly information (maybe with a bit of verification code) instead of extended to *doing* things that derive mainly from *our* particular ways of using them. Because to the user of those methods on Interface, it looks exactly like the packa does have such knowledge. We shouldn't lie.ge I don't think that we lie as long as we state that we have a plugin system of any kind (including monkey-patching, for the sake of
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Thomas Lotze wrote: Chris McDonough wrote: I'll throw out the obvious... Why not subclass Interface in zope.component and make the required API additions there? If it were anybody but us thinking about doing this, they'd probably just subclass. Because then, if you use third-party code that uses zope.interface.Interface and other code (third-party or your own) that uses the subclassed interfaces, you'll have to deal with both types at the same time in your client code. You could use the new API on some interfaces but not on others, possibly on the same line of code. How readable or maintainable would such code be? I'm not sure, but if we had it to do all over again, this would be an obvious solution. It would be the work of maybe two days to convert all ZTK packages to use a z.c.interface.Interface, and any existing package would need to be touched anyway to use .adapt and .utility. So it bears some weight I think, even if it is eventually rejected. - C ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Chris McDonough wrote: Thomas Lotze wrote: Because then, if you use third-party code that uses zope.interface.Interface and other code (third-party or your own) that uses the subclassed interfaces, you'll have to deal with both types at the same time in your client code. You could use the new API on some interfaces but not on others, possibly on the same line of code. How readable or maintainable would such code be? I'm not sure, but if we had it to do all over again, this would be an obvious solution. It would be the work of maybe two days to convert all ZTK packages to use a z.c.interface.Interface, and any existing package would need to be touched anyway to use .adapt and .utility. So it bears some weight I think, even if it is eventually rejected. It does certainly bear some weight as one possibility to be considered. However, my point wasn't so much about converting a limited existing amount of code; you're obviously right about having to touch that anyway in order to use the new methods. My objection is this: If we go to the trouble of implementing basic interfaces in zope.interface plus derived ones with component lookup capabilities in zope.component and keep both around for their respective reasons of existence, then it is expected that there will be code that uses both types of interfaces for these very reasons (and maybe other types which have other added behaviour). Such code would become a lot less maintainable since you'd never know whether a given interface has a particular method just because the one next to it does. OTOH, registering all behaviour an application needs onto the same interface type doesn't create that problem. As long as you're familiar with the application at large, you will know for every interface that occurs in it which methods is has, how they need to be called and what their semantics are. Also, subclassing for adding behaviour introduces the typical problems of hierarchies and tight coupling. This isn't a practical problem as long as we only ever talk about adaptation as the only use of interfaces, but I'm trying to discuss interfaces as a language feature with a greater set of possible use cases. -- Thomas ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Chris McDonough wrote: I'll throw out the obvious... Why not subclass Interface in zope.component and make the required API additions there? If it were anybody but us thinking about doing this, they'd probably just subclass. Because then, if you use third-party code that uses zope.interface.Interface and other code (third-party or your own) that uses the subclassed interfaces, you'll have to deal with both types at the same time in your client code. You could use the new API on some interfaces but not on others, possibly on the same line of code. How readable or maintainable would such code be? -- Thomas ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
* Martijn Faassen faas...@startifact.com [2009-12-17 17:48]: * Thomas Lotze t...@gocept.com: zope.interface [should be] completely unaware of any particular uses of interfaces Why is it a problem that the zope.interface package gains knowledge about adaptation (which it always had, anyway) and utility lookup? This is the key issue, I think. (And I'd like to ask you not to argue it has always been that way, since what we're trying to do here precisely is to improve the status quo.) The question is, which concepts belong into zope.interface and which don't? One might also phrase that as, what is the responsibility and purpose of zope.interface (drawing upon the software engineering terms of cohesion and coupling). My opinion is that [__call__ introduces] the following notion into zope.interface: please look up an object that provides this interface, somehow. (with zero or more context objects) might well belong into zope.interface, but that anything of these: adapters, utilities, null-adapters or contextual utilities absolutely do not. I think there is a clear distinction between what interfaces are about and what component architecture is about, and I think it is worthwile to maintain and clarify that distinction. For me, a notion of looking up something that provides an interface belongs to what interfaces are about. But notions of utilities which might or might not be singletons, of adapters which might or might not take additional parameters such as a name to look them up, or notions of a context or a registry (which for me comes up immediately when thinking about global vs. local utilities) that influences the lookup, for me emphatically do *not* belong to what interfaces are about. By putting method stubs into zope.interface which are exclusively about concepts of zope.component we would be a) On a conceptual level: blurring the distinction between the two packages and concepts, which I think is a Bad Thing(tm) b) On a more practical level: coupling zope.interface to zope.component. Given all the recent efforts of untangling the dependency structure between our packages, I think doing that would be a step in the exact opposite direction. Wolfgang ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Wolfgang Schnerring wrote: * Martijn Faassen faas...@startifact.com [2009-12-17 17:48]: * Thomas Lotze t...@gocept.com: zope.interface [should be] completely unaware of any particular uses of interfaces Why is it a problem that the zope.interface package gains knowledge about adaptation (which it always had, anyway) and utility lookup? This is the key issue, I think. (And I'd like to ask you not to argue it has always been that way, since what we're trying to do here precisely is to improve the status quo.) I'm saying that because I don't recall people arguing against this before. Since the __call__ logic is only about adapter lookup, does this mean that your argument is expanded against this as well or does it fall under the notion of looking up anything by interface? I think from the rest of your mail that you mean the latter. At least it's a strict subset of an expanded notion of lookup. [snip] By putting method stubs into zope.interface which are exclusively about concepts of zope.component we would be I would say that to be consistent in that position, you would need to argue not just against method stubs but against the presence of these methods at all, no matter where they come from. The rest is just an implementation detail. Reasoning from your position that zope.interface shouldn't have notions of adapter and utility lookup, it hardly matters what package implements these methods. To the user of Interface it will look the same, except that zope.component monkey-patching things in would be harder to understand and debug. To be consistent we have the following options: * only provide a general notion of looking up something by interface in zope.interface. This general notion unfortunately clearly doesn't have support from a large number of people so sadly I had to let that go. * not change anything at all. Looking up these things remains the task of zope.component and we better use zope.component APIs. Monkey-patching methods in from another package to me looks like it doesn't improve the conceptual story at all. Conceptually Interface ends up as messed up as before and it becomes more difficult to understand what's going on for the code reader or debugger. which might or might not take additional parameters such as a name to look them up ... for me emphatically do *not* belong to what interfaces are about. I think you can see a name as another context in a multi-adaptation, where this context is special in that: * it needs to be human-readable text * it cannot extend another name, unlike interfaces, which can extend each other It's just a handy shortcut. :) By putting method stubs into zope.interface which are exclusively about concepts of zope.component we would be a) On a conceptual level: blurring the distinction between the two packages and concepts, which I think is a Bad Thing(tm) b) On a more practical level: coupling zope.interface to zope.component. Given all the recent efforts of untangling the dependency structure between our packages, I think doing that would be a step in the exact opposite direction. I don't think the dependency refactoring argument holds. We were untangling physical dependencies. This wouldn't change physical dependencies one bit: zope.component would still depend on zope.interface. There are likely tons of places where package A depends on package B and also configures package B, changing its behavior. This would be no different: zope.component depends on zope.interface and plugs into it as well to configure some of its behavior. That's what it does today with the adapter hook. Putting notions of conceptual purity aside, I was arguing for a pragmatic solution that results in code that is as unsurprising as possible. I don't think .adapt and .utility are perfect, and I would have gone for another solution myself (a more generalized lookup method), but they seem to have consensus support. I don't think they do much in the way of active harm by being there in zope.interface. They help readability of the code that uses them. Moreover, this pragmatic solution would make code that looks up multi adapters and utilities more convenient to write. So, zope.interface needs to gain these methods, and open up a plugin point so that these methods can be fully implemented by another package. I think this can be constructed so that the only new notions to zope.interface are: * multi-adaptation, an extension of adaptation * look up by name, a conceptual extension of multi-adaptation :) * utility lookup Too many for my tastes when there's such an elegant general lookup method available, but I can't convince enough people of that. If we are going to make Interface support these methods for pragmatic considerations, we should just face it and implement them on Interface (delegating to a plugin). Anything else just helps to obfuscate what is going on. Regards, Martijn
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
On Fri, Dec 18, 2009 at 08:51, Brian Sutherland br...@vanguardistas.net wrote: I like things to fail noisily and loudly unconfigured and give good information about what's wrong. +1 So my preferred implementation of a stub utility function on Interface is: def utility(default=None): Lookup a utility for this interface. A utility is a ${long explanation of utility concept}. This method behaves like ${explanation of utility method contract}. raise NotImplementedError(No Utility lookup mechanism has been configured. If you wish to use utility lookups on interfaces, please configure a package that contains this mechanism. Packages known to implement this are: zope.component ) I agree that this encodes in the zope.interface package concepts from zope.component. I think that is stretching the encoding concepts a bit too far. Yes, we make zope.interface aware that such a thing as utility-registries exist, but say we don't implement it. I don't think that's a problem. The error message also gives an example of an implementation. That's probably not a problem either. I feel uncomfortable about that. I don't. :-) -- Lennart Regebro: http://regebro.wordpress.com/ Python 3 Porting: http://python-incompatibility.googlecode.com/ +33 661 58 14 64 ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Hi, On Fri, Dec 18, 2009 at 9:47 AM, Lennart Regebro rege...@gmail.com wrote: On Fri, Dec 18, 2009 at 08:51, Brian Sutherland br...@vanguardistas.net wrote: I like things to fail noisily and loudly unconfigured and give good information about what's wrong. +1 [snip] we make zope.interface aware that such a thing as utility-registries exist, but say we don't implement it. I don't think that's a problem. The error message also gives an example of an implementation. That's probably not a problem either. I feel uncomfortable about that. I don't. :-) +1 from my perspective of I don't know or understand the core ZCA codebase very well (and don't understand all the implications in this discussion) but often read or trace through the code. A well-documented NotImplementedError seems much more human-useful than a default implementation that fulfills the contract, because it assertively announces the expectation for the most common case by far: you probably want to plug in a real implementation here. Then if there is a need for the proposed default implementation, it can be provided as a plugin by some other package, right? -Ethan ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Ethan Jucovy wrote: +1 from my perspective of I don't know or understand the core ZCA codebase very well (and don't understand all the implications in this discussion) but often read or trace through the code. A well-documented NotImplementedError seems much more human-useful than a default implementation that fulfills the contract, because it assertively announces the expectation for the most common case by far: you probably want to plug in a real implementation here. Then if there is a need for the proposed default implementation, it can be provided as a plugin by some other package, right? I'm now convinced people want to see a clear NotImplementedError. I think if we went with a plugin structure, we could do something like this: class Interface: ... def utility(...): return lookup_plugin.utility(...) class NotImplementedLookupPlugin(object): def utility(...): raise NotImplementedError( this is the not implemented lookup plugin. You need to install another one. Blah blah zope.component blah blah) lookup_plugin = NotImplementedLookupPlugin() def set_lookup_plugin(plugin): global lookup_plugin lookup_plugin = plugin As long as external packages do not register a proper plugin, it'll raise NotImplementedErrors. Both the actual error as well as the name of the default lookup plugin signal something hasn't been installed. We could also easily provide *another* plugin in zope.interface that does the as if the registry is empty behavior, if that turns out to be useful (perhaps for testing). But to use it someone would need to explicitly enable it. Tests could also define fake lookup plugins with other behavior so we can test these methods properly. Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Ethan Jucovy wrote: Hi, On Fri, Dec 18, 2009 at 9:47 AM, Lennart Regebro rege...@gmail.com wrote: On Fri, Dec 18, 2009 at 08:51, Brian Sutherland br...@vanguardistas.net wrote: I like things to fail noisily and loudly unconfigured and give good information about what's wrong. +1 [snip] we make zope.interface aware that such a thing as utility-registries exist, but say we don't implement it. I don't think that's a problem. The error message also gives an example of an implementation. That's probably not a problem either. I feel uncomfortable about that. I don't. :-) +1 from my perspective of I don't know or understand the core ZCA codebase very well (and don't understand all the implications in this discussion) but often read or trace through the code. A well-documented NotImplementedError seems much more human-useful than a default implementation that fulfills the contract, because it assertively announces the expectation for the most common case by far: you probably want to plug in a real implementation here. Then if there is a need for the proposed default implementation, it can be provided as a plugin by some other package, right? The same argument applies in your case: you could plug in your own wrapper implementation which raised errors if not replaced. - -1 to raising NotImplementedError. Tres. - -- === Tres Seaver +1 540-429-0999 tsea...@palladion.com Palladion Software Excellence by Designhttp://palladion.com -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.9 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkssANoACgkQ+gerLs4ltQ57XgCdGN8W4q4IevSbQX+XgaRaUXA4 rNkAn1ART1odK+s576b8GbjGX6JIJh6u =VJnE -END PGP SIGNATURE- ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
[Zope-dev] A summary of Interfaces vs ZCA concepts
Hi there, Here's a summary of what has been going on in this thread with some attempts at conclusions that have support of the consensus so that Thomas can proceed * We want to implement .adapter(), .utility() and .__call__() in zope.component as much as possible. * we want a similar mechanism for each of them to plug in. * It'd be nice if __call__ came back with a LookupError instead of a TypeError, but how to get from A to B without breakage? * there was some discussion about general plugin points on Interface. Those have a complexity cost compared to simply poking the methods into the class. * the methods can be on zope.interface even if zope.component isn't installed. They will behave as if the component registry is empty. Their behavior should be: IFoo.adapt(context) raises LookupError, unless the context provides IFoo, in which case it returns context. IFoo.adapt(context, default=default) returns default unless context provides IFoo, in which case it returns context. IFoo.utility() raises LookupError. IFoo.utility(default=default) returns default What's the behavior of __call__ now if zope.component isn't around? * Tres brought up that we can come up with a clean plugin interface instead, and now I'm tempted to go for that instead of monkey-ing around. What if there's some global object that zope.component can register into that has this API? class ILookupPlugin(Interface): def singleAdapt(interface, context): Look up an adapter that provides interface in the adapter registry for context. If no adapter can be found, raise LookupError. ( (or return None or another sentinel? See below for an argument in favor of LookupError) def multiAdapt(interface, contexts): Look up an adapter that provides interface for contexts. def utility(interface): Lookup an utility that provides interface. And a way to register this into zope.interface (globally): def registerLookupPlugin(plugin): ... The default plugin provided by zope.interface always raises ComponentLookupError (or returns the sentinel). The plugin is not responsible for handling defaults, just registry lookups. Then the code in __call__, adapt and utility can: * check whether the context (if available) already provides interface, return that. * look up in the plugin * if the plugin raises (or returns sentinel) and there is a default, return default * if there no default, raise LookupError. I think we can turn the message from ComponentLookupError into a LookupError fairly safely, so I think having the plugin raise exceptions is better as it retains more information. In fact it'd be entirely safe to just reraise ComponentLookupError as we only specify LookupError in the API and the ComponentLookupError *is* a LookupError I realize that the proposal for a plugin API gives zope.interface some knowledge about adaption and utility lookups, which is what Thomas and Wolfgang had trouble with. But after all that's what we're doing anyway by putting those methods on the API, one way or another. And we can define sensible enough behavior even if zope.component is not installed. If someone comes up with *another* implementation besides zope.component, say, zope.component2, zope.interface could cleanly deal with that too. [Philosophically from my own perspective I think we'd have much less conceptual difficulty with this if we just made __call__ do all lookups, as that hides the whole set of concepts of utility versus adapter a bit, but we can't get consensus for that unfortunately. But I'm biding my time..] Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Hi, On Thu, Dec 17, 2009 at 10:15 AM, Martijn Faassen faas...@startifact.com wrote: * It'd be nice if __call__ came back with a LookupError instead of a TypeError, but how to get from A to B without breakage? Maybe I've misunderstanding, but what's the advantage of making IFoo(x) raise a LookupError instead of a TypeError? I've tried to follow the thread but I've been confused about this. I do rely on catching TypeErrors quite often in my code -- I had thought it was intended as part of the API. I like that treating it as typecasting instead of lookup blurs the conceptual distinction between adapting x to IFoo and asserting x implements IFoo directly -- when I actually want to know one or the other I can use explicit adaptation or check providedBy. In other words I use IFoo(x) when I don't care whether IFoo(x) == x. I suppose it's not a big deal but catching LookupErrors instead would feel somewhat less semantic for the way I think about this. But from what I've caught of the larger thread it sounds like I'm in the minority here. -Ethan ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
On 12/17/09 16:36 , Ethan Jucovy wrote: Hi, On Thu, Dec 17, 2009 at 10:15 AM, Martijn Faassen faas...@startifact.com wrote: * It'd be nice if __call__ came back with a LookupError instead of a TypeError, but how to get from A to B without breakage? Maybe I've misunderstanding, but what's the advantage of making IFoo(x) raise a LookupError instead of a TypeError? I've tried to follow the thread but I've been confused about this. I do rely on catching TypeErrors quite often in my code -- I had thought it was intended as part of the API. I like that treating it as typecasting instead of lookup blurs the conceptual distinction between adapting x to IFoo and asserting x implements IFoo directly -- when I actually want to know one or the other I can use explicit adaptation or check providedBy. In other words I use IFoo(x) when I don't care whether IFoo(x) == x. I suppose it's not a big deal but catching LookupErrors instead would feel somewhat less semantic for the way I think about this. But from what I've caught of the larger thread it sounds like I'm in the minority here. Perhapse LookupError should be a subclass of TypeError. Wichert. ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Hey, Ethan Jucovy wrote: On Thu, Dec 17, 2009 at 10:15 AM, Martijn Faassen faas...@startifact.com wrote: * It'd be nice if __call__ came back with a LookupError instead of a TypeError, but how to get from A to B without breakage? Maybe I've misunderstanding, but what's the advantage of making IFoo(x) raise a LookupError instead of a TypeError? I've tried to follow the thread but I've been confused about this. I do rely on catching TypeErrors quite often in my code -- I had thought it was intended as part of the API. Consistency. The other lookup APIs in zope.component raise ComponentLookupError, which is a kind of LookupError. Good data point about catching TypeError though - I don't think we can just make a release that breaks this. I like that treating it as typecasting instead of lookup blurs the conceptual distinction between adapting x to IFoo and asserting x implements IFoo directly -- when I actually want to know one or the other I can use explicit adaptation or check providedBy. In other words I use IFoo(x) when I don't care whether IFoo(x) == x. Yeah, TypeError makes sense from the type casting perspective. Perhaps my earlier idea about a new Error that subclasses both TypeError and LookupError isn't so ugly after all.. After all a failure to look up an adapter can easily be interpreted as both. Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Martijn Faassen wrote: Here's a summary of what has been going on in this thread with some attempts at conclusions that have support of the consensus so that Thomas can proceed Thank you, half an hour later and I'd have written the summary ;o) * We want to implement .adapter(), .utility() and .__call__() in zope.component as much as possible. The method's name is `adapt`, JFTR. * we want a similar mechanism for each of them to plug in. Agreed, even though (AFAICT) we haven't been talking about moving the implementation of __call__ to zope.component so far. * It'd be nice if __call__ came back with a LookupError instead of a TypeError, but how to get from A to B without breakage? It's not possible without breakage. I'd say changing the error is worth a 4.0 release, but we might want to postpone this change and see whether there's anything else we want to change about zope.interface in a backwards-incompatible way, and if so, put that in the 4.0 release as well. I guess we don't want too many backwards-incompatible releases of such a central package. One thing I start questioning is an adapter registry being implemented by zope.interface. Moving it to zope.component seems to me to be related to keeping the implementations of the new method within zope.component. * there was some discussion about general plugin points on Interface. Those have a complexity cost compared to simply poking the methods into the class. As for poking the methods into the class, see the new tlotze-patching-interfaces branches of zope.interface and zope.component for the minimum change this would take IMO. The change to zope.interface is really just about documentation. * the methods can be on zope.interface even if zope.component isn't installed. They will behave as if the component registry is empty. This isn't covered by the consensus you mentioned above as far as I'm concerned. Their behavior should be: IFoo.adapt(context) raises LookupError, unless the context provides IFoo, in which case it returns context. IFoo.adapt(context, default=default) returns default unless context provides IFoo, in which case it returns context. IFoo.utility() raises LookupError. IFoo.utility(default=default) returns default I think looking at that API explains why we have trouble with having stub methods defined by zope.interface: these methods contain enough information about component concepts to blur the distinction between zope.interface and zope.component, but they still lie about the actual method signature. In that sense, these stubs would be worse than zope.interface not documenting the methods at all. In my and Wolfgang's opinion, we can either have zope.interface implement methods with the real contract, which would mean defining the full concepts of the ZCA within zope.interface (if not their implementation), or not even have method stubs in zope.interface and leave the whole business of defining specialised uses of interfaces to other packages such as zope.component. What's the behavior of __call__ now if zope.component isn't around? Similar to what you've just described of your `adapt` method, up to the name of the `default` parameter and the exception raised. * Tres brought up that we can come up with a clean plugin interface instead, and now I'm tempted to go for that instead of monkey-ing around. [...] I'd have to think about that some more, but while reading it the first time, it feels quite wrong to me. I realize that the proposal for a plugin API gives zope.interface some knowledge about adaption and utility lookups, which is what Thomas and Wolfgang had trouble with. But after all that's what we're doing anyway by putting those methods on the API, one way or another. No: the zope.interface package doesn't have any knowledge about the particulars of any of the uses of interfaces. One might claim that interfaces do after they've been patched by other code, but then, that's after some application has made its choice about plugin certain packages together. It's not baked into zope.interface, and that's what we're trying so hard to achieve. [Philosophically from my own perspective I think we'd have much less conceptual difficulty with this if we just made __call__ do all lookups, as that hides the whole set of concepts of utility versus adapter a bit, but we can't get consensus for that unfortunately. But I'm biding my time..] Implementing __call__ within zope.interface in that way would get the package rid of the method names `adapt` and `utility`, but the technical problem with the method signatures and the more philosophical one about whether zope.interface should really make adaptation stand out as a use of interfaces remains. Which brings me back to the question I asked earlier, and which nobody has replied to so far: Do we want to make zope.interface completely unaware of any particular uses of interfaces, or do we want to treat component lookup and in particular
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Wichert Akkerman wrote: [knip] Perhapse LookupError should be a subclass of TypeError. It's a Python built-in. :) Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Hey, Thomas Lotze wrote: [snip] * We want to implement .adapter(), .utility() and .__call__() in zope.component as much as possible. The method's name is `adapt`, JFTR. Whoops, yes, I prefer 'adapt' actually anyway. :) * we want a similar mechanism for each of them to plug in. Agreed, even though (AFAICT) we haven't been talking about moving the implementation of __call__ to zope.component so far. I figured we'd want to treat each of them in the same way. * It'd be nice if __call__ came back with a LookupError instead of a TypeError, but how to get from A to B without breakage? It's not possible without breakage. Unless we create a zope.interface specific LookupError which subclasses both the built-in LookupError and TypeError. zope.component's ComponentLookupError should subclass this special LookupError then. One thing I start questioning is an adapter registry being implemented by zope.interface. Moving it to zope.component seems to me to be related to keeping the implementations of the new method within zope.component. I'm not sure where that stuff should be. I'll defer some of this to Gary again, who is interested in working on this topic. :) [snip] * the methods can be on zope.interface even if zope.component isn't installed. They will behave as if the component registry is empty. This isn't covered by the consensus you mentioned above as far as I'm concerned. Yeah, I put that in so we can reach consensus on it. I thought Tres had a good idea going on there that makes the plugin behavior a lot cleaner. Their behavior should be: IFoo.adapt(context) raises LookupError, unless the context provides IFoo, in which case it returns context. IFoo.adapt(context, default=default) returns default unless context provides IFoo, in which case it returns context. IFoo.utility() raises LookupError. IFoo.utility(default=default) returns default I think looking at that API explains why we have trouble with having stub methods defined by zope.interface: these methods contain enough information about component concepts to blur the distinction between zope.interface and zope.component, but they still lie about the actual method signature. I don't understand you: why do you say they lie about their method signature? They should have the same signature and have a well-defined behavior if zope.component is not installed: there is nothing registered at all. zope.interface provides a plugin point that allows one to plug lookup behavior into it. In that sense, these stubs would be worse than zope.interface not documenting the methods at all. I strongly disagree. We want to define a bunch of methods on Interface that we want everybody to have access to. We can't then turn around and say we really actually don't want to implement those methods on Interface. That Interface *delegates* the implementation to something else is fine, but the methods are conceptually on Interface, and delegation is normally implemented by just calling the code we delegate to. In my and Wolfgang's opinion, we can either have zope.interface implement methods with the real contract, which would mean defining the full concepts of the ZCA within zope.interface (if not their implementation), or not even have method stubs in zope.interface and leave the whole business of defining specialised uses of interfaces to other packages such as zope.component. In that case, I want the real contract to be in zope.interface. That's where the methods are, after all. We need to talk about the concept of an adapter and a utility briefly in zope.interface and defer to zope.component as the most common implementation. We already have this kind of behavior going on anyway with __call__() (even though not documented!). What's the behavior of __call__ now if zope.component isn't around? Similar to what you've just described of your `adapt` method, up to the name of the `default` parameter and the exception raised. So if no registry is available (zope.component not installed), you can still call it and it'll just behave as if the registry is empty? That's good.. * Tres brought up that we can come up with a clean plugin interface instead, and now I'm tempted to go for that instead of monkey-ing around. [...] I'd have to think about that some more, but while reading it the first time, it feels quite wrong to me. You'll have to go into more detail. Why does it feel wrong to you? It's the way plugin APIs generally tend to work. You could even look up this API as a utility - but that's probably a chicken and egg problem. :) [see below for a possible improvement on this API] I realize that the proposal for a plugin API gives zope.interface some knowledge about adaption and utility lookups, which is what Thomas and Wolfgang had trouble with. But after all that's what we're doing anyway by putting those methods on the API, one way or another. No: the zope.interface package
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
I'll throw out the obvious... Why not subclass Interface in zope.component and make the required API additions there? If it were anybody but us thinking about doing this, they'd probably just subclass. - C Martijn Faassen wrote: Wichert Akkerman wrote: [knip] Perhapse LookupError should be a subclass of TypeError. It's a Python built-in. :) Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope ) ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Yeah, I was thinking that too, as a I don't have time to think hard about this little daydream. Actually I believe you would want to subclass InterfaceClass and make your new zope.component.Interface an instance of the new InterfaceClass and specify zope.interface's Interface as something it extends. Then packages in the Zope world would start to use that Interface, I'd guess. I don't know how I feel about it. Gary On Dec 17, 2009, at 11:51 AM, Chris McDonough wrote: I'll throw out the obvious... Why not subclass Interface in zope.component and make the required API additions there? If it were anybody but us thinking about doing this, they'd probably just subclass. - C Martijn Faassen wrote: Wichert Akkerman wrote: [knip] Perhapse LookupError should be a subclass of TypeError. It's a Python built-in. :) Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope ) ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope ) ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
We've been through this option recently already. It has been quickly shot down by those who want interfaces to get the new behaviour immediately available in existing interfaces, instead of having to rewrite already existing interfaces to support the new API. Painful memories of a time when we had 2 interface implementations come to mind. Though in this case, with z.c.Interface extending z.i.Interface, we probably wouldn't have so much backward compatibility issues as we had before: the new API would just not be available in non migrated code, and old code could treat z.c.Interfaces just like z.i.Interfaces. On Thu, Dec 17, 2009 at 15:07, Gary Poster gary.pos...@gmail.com wrote: Yeah, I was thinking that too, as a I don't have time to think hard about this little daydream. Actually I believe you would want to subclass InterfaceClass and make your new zope.component.Interface an instance of the new InterfaceClass and specify zope.interface's Interface as something it extends. Then packages in the Zope world would start to use that Interface, I'd guess. I don't know how I feel about it. Gary On Dec 17, 2009, at 11:51 AM, Chris McDonough wrote: I'll throw out the obvious... Why not subclass Interface in zope.component and make the required API additions there? If it were anybody but us thinking about doing this, they'd probably just subclass. - C Martijn Faassen wrote: Wichert Akkerman wrote: [knip] Perhapse LookupError should be a subclass of TypeError. It's a Python built-in. :) Regards, Martijn ___ Zope-Dev maillist - zope-...@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope ) ___ Zope-Dev maillist - zope-...@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope ) ___ Zope-Dev maillist - zope-...@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope ) ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Chris McDonough wrote: I'll throw out the obvious... Why not subclass Interface in zope.component and make the required API additions there? If it were anybody but us thinking about doing this, they'd probably just subclass. Because then we'd need to rebase all our interfaces to be able to use the new feature, making it pretty useless as a handy shortcut. regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Martijn Faassen wrote: Chris McDonough wrote: I'll throw out the obvious... Why not subclass Interface in zope.component and make the required API additions there? If it were anybody but us thinking about doing this, they'd probably just subclass. Because then we'd need to rebase all our interfaces to be able to use the new feature, making it pretty useless as a handy shortcut. I guess the counterargument is that you need to change your code anyway to make use of the new feature. So what's the difference? - C ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Chris McDonough wrote: Martijn Faassen wrote: Chris McDonough wrote: I'll throw out the obvious... Why not subclass Interface in zope.component and make the required API additions there? If it were anybody but us thinking about doing this, they'd probably just subclass. Because then we'd need to rebase all our interfaces to be able to use the new feature, making it pretty useless as a handy shortcut. I guess the counterargument is that you need to change your code anyway to make use of the new feature. So what's the difference? I'm a bit surprised I need to spell it out, so perhaps I am missing something. With your subclass proposal, if I use package a.b.c that defines an interface, and I import that interface and want to use the new feature, I'd need to change package a.b.c to make use of the new feature. That's a code change (changing the interface import), and a dependency change (making sure the new version of zope.component is in use), and a release. I need to do that for all packages I import interfaces from. I need to *know* which packages have been updated or have things blow up on me. That's quite a hassle. The end result would be that everybody ends up inheriting from the new zope.component Interface just to get access to the new methods everywhere, or that the new methods don't get uptake from users as nobody bothers to use the new API because it is too much work changing your dependencies. If we change the Interface base class, I could use the new feature with any interface coming from anywhere. I'd only need to make sure that my own package depends on a newer version of zope.interface (or possibly a newer version of zope.component, depending on the way these methods are implemented). Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
On Thu, Dec 17, 2009 at 05:48:04PM +0100, Martijn Faassen wrote: Thomas Lotze wrote: I think looking at that API explains why we have trouble with having stub methods defined by zope.interface: these methods contain enough information about component concepts to blur the distinction between zope.interface and zope.component, but they still lie about the actual method signature. I don't understand you: why do you say they lie about their method signature? They should have the same signature and have a well-defined behavior if zope.component is not installed: there is nothing registered at all. zope.interface provides a plugin point that allows one to plug lookup behavior into it. In that sense, these stubs would be worse than zope.interface not documenting the methods at all. I strongly disagree. We want to define a bunch of methods on Interface that we want everybody to have access to. We can't then turn around and say we really actually don't want to implement those methods on Interface. That Interface *delegates* the implementation to something else is fine, but the methods are conceptually on Interface, and delegation is normally implemented by just calling the code we delegate to. I'd like to advance the following argument that I haven't seen yet in this thread: discoverability. Specifically, letting the developer figure out what's happening. When I see code like this: formatter = IHTMLFormatter(widget).to_html() I can look up the definition of IHTMLFormatter, see that it's a class inheriting from Interface, look up zope.interface.Interface, see that it's an InterfaceClass instance, look up InterfaceClass.__call__ to see what it does -- checks for widget.__conform__, checks if widget provides IHTMLFormatter directly, loops through adapter_hooks. Then I can grep for adapter_hooks in my buildout omelette tree and find that zope.component hooks into it. And so on. If there's only monkey-patching going on, I'd get stuck in step 4: InterfaceClass has no __call__. Where does it come from? Monkey-patching is sufficiently frowned-upon in the Python world that it wouldn't occur for me to recursively grep InterfaceClass.__call__ =; I'd assume I missed something and run in circles. The main point of my email completed, I still cannot force myself to desist from further comments. In my and Wolfgang's opinion, we can either have zope.interface implement methods with the real contract, which would mean defining the full concepts of the ZCA within zope.interface (if not their implementation), or not even have method stubs in zope.interface and leave the whole business of defining specialised uses of interfaces to other packages such as zope.component. In that case, I want the real contract to be in zope.interface. That's where the methods are, after all. We need to talk about the concept of an adapter and a utility briefly in zope.interface and defer to zope.component as the most common implementation. We already have this kind of behavior going on anyway with __call__() (even though not documented!). It'd be simpler if utilities didn't exist as a concept in zope.interface, but y'all have decided that's too ambitious. (Personally I kinda think redesigning zope.component/zope.interface APIs is too ambitious; the Zope community would be better served by having a website with up-to-date documentation of everything, launchpad bug trackers for every package in the ZTK and KGS, stable and regular ZTK and KGS releases, etc. But I know that I have no right to tell anyone what they should work on instead of their chosen pet project.) What's the behavior of __call__ now if zope.component isn't around? Similar to what you've just described of your `adapt` method, up to the name of the `default` parameter and the exception raised. So if no registry is available (zope.component not installed), you can still call it and it'll just behave as if the registry is empty? That's good.. (Unless it trips people up leading them to assume they made a mistake in their adapter/utility registrations, when they instead forgot to register the hook. But that's unlikely, as I've already said elsewhere.) Marius Gedminas -- http://pov.lt/ -- Zope 3 consulting and development signature.asc Description: Digital signature ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
Hey, Marius Gedminas wrote: I'd like to advance the following argument that I haven't seen yet in this thread: discoverability. I was actually thinking very much about people who read the code all the time, but apparently I wasn't very clear. That's also why I moved away from a position of monkey patching to a plugin API. [snip] If there's only monkey-patching going on, I'd get stuck in step 4: InterfaceClass has no __call__. Where does it come from? Monkey-patching is sufficiently frowned-upon in the Python world that it wouldn't occur for me to recursively grep InterfaceClass.__call__ =; I'd assume I missed something and run in circles. I agree. I think therefore we should put implementations in zope.interface, that can defer to a plugin registered by zope.component, just as we have for the adapter hook. (though I think we can come up with a more straightforward pattern than the whole hookable stuff, which I think I understood once but have since forgotten :) [snip] It'd be simpler if utilities didn't exist as a concept in zope.interface, but y'all have decided that's too ambitious. (Personally I kinda think redesigning zope.component/zope.interface APIs is too ambitious; the Zope community would be better served by having a website with up-to-date documentation of everything, launchpad bug trackers for every package in the ZTK and KGS, stable and regular ZTK and KGS releases, etc. But I know that I have no right to tell anyone what they should work on instead of their chosen pet project.) I think the Zope community needs to be able to do all these things (which I've personally invested quite a bit of time on improving as well) *and* improve the ZCA APIs. Some people ask why explore the solar system when world hunger isn't yet solved?. Lots of people have lots of cogent answers to that question. We need project infrastructure, yes, but we also need a community: * where ideas arise that when implemented affect a lot of people * where we can discuss such ideas * where we have people and mechanisms to reach such discussions to a *conclusion* * where we have volunteers who actually implement the conclusion If we don't have that, we don't have a functional community *either*. We'll always be in maintenance mode. What's the behavior of __call__ now if zope.component isn't around? Similar to what you've just described of your `adapt` method, up to the name of the `default` parameter and the exception raised. So if no registry is available (zope.component not installed), you can still call it and it'll just behave as if the registry is empty? That's good.. (Unless it trips people up leading them to assume they made a mistake in their adapter/utility registrations, when they instead forgot to register the hook. But that's unlikely, as I've already said elsewhere.) Yeah, I sympathise. I believe this is an unfortunate consequence of any plugin system. To mitigate that issue, I think clear warning signs are needed in zope.interface's dummy plugin so that people who step into it get a clear clue something didn't get registered right. Regards, Martijn ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Re: [Zope-dev] A summary of Interfaces vs ZCA concepts
On Thu, Dec 17, 2009 at 04:59:12PM +0100, Thomas Lotze wrote: Martijn Faassen wrote: Their behavior should be: IFoo.adapt(context) raises LookupError, unless the context provides IFoo, in which case it returns context. IFoo.adapt(context, default=default) returns default unless context provides IFoo, in which case it returns context. IFoo.utility() raises LookupError. IFoo.utility(default=default) returns default I think looking at that API explains why we have trouble with having stub methods defined by zope.interface: these methods contain enough information about component concepts to blur the distinction between zope.interface and zope.component, but they still lie about the actual method signature. In that sense, these stubs would be worse than zope.interface not documenting the methods at all. In my and Wolfgang's opinion, we can either have zope.interface implement methods with the real contract, which would mean defining the full concepts of the ZCA within zope.interface (if not their implementation), or not even have method stubs in zope.interface and leave the whole business of defining specialised uses of interfaces to other packages such as zope.component. I like things to fail noisily and loudly unconfigured and give good information about what's wrong. So my preferred implementation of a stub utility function on Interface is: def utility(default=None): Lookup a utility for this interface. A utility is a ${long explanation of utility concept}. This method behaves like ${explanation of utility method contract}. raise NotImplementedError(No Utility lookup mechanism has been configured. If you wish to use utility lookups on interfaces, please configure a package that contains this mechanism. Packages known to implement this are: zope.component ) I agree that this encodes in the zope.interface package concepts from zope.component. I feel uncomfortable about that. But I feel more uncomfortable with magic where it is impossible to find out what is going on by reading the code. -- Brian Sutherland ___ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )