[Zope-dev] make zope.component.registry.Components inherit from dict?

Martin Aspeli optilude+lists at gmail.com
Tue Nov 24 00:54:26 EST 2009


Hi Chris,

Chris McDonough wrote:
> Martin Aspeli wrote:
>> We need to make sure that we're not inventing a different way to achieve 
>> something which is already possible. This will lead to confusion, 
>> because people will have to know "which way" is applicable in a given 
>> situation, and the distinction will seem arbitrary.
> 
> I fear we are indeed inventing a different way to achieve something which is 
> already possible.  We aren't doing it arbitrarily, though: the current way just 
> requires the use of an interface instead of a string.  Interface usage for such 
> a simple pattern implies a cognitive load that appears to exceed the pain point 
> of most Python developers who are not already familiar with Zope.  So we'd like 
> to ameliorate that as best we can.

I wish I knew what "ameliorate" meant, but I'm sure I agree.

My concern is that we also have a pretty large existing user base to 
worry about, and we wouldn't want to confuse them. Or, indeed, new users 
confronted with code that has been written up to this point.

>   >> In a system like this, there are no interfaces; the string 'root_factory'
>>> performs the same job as the IRootFactory interface for registration and 
>>> lookup.  I'd like to make the ZCA registry operate like this.  There's really 
>>> no reason for there to be an interface hanging around to represent this thing: 
>>> we're using the ZCA as a complicated dictionary here.
>> I think there is a reason, though you may not agree it's a good one. The 
>> interface makes a promise about what the component is supposed to be 
>> able to do. We don't enforce that in our duck-typing programming 
>> language, but I think there is value in being able to say, "I want an 
>> object that conforms to this interface (i.e. delivers what the interface 
>> promises) - please get me the best one you've got".
> 
> That is indeed the promise.  But obviously the object you get back needn't 
> *actually* implement the interface you asked for; it's only conventional.  It 
> is the same with a dictionary lookup: if you document that, for your 
> application, reg['root_factory'] will return an object implementing 
> IRootFactory, it's pretty much equivalent as far as I can tell.  Use of the ZCA 
> API to store and retrieve instances implementing an interface isn't required to 
> get benefit out of the existence of that interface.

No, that's true, except perhaps that it's two things to worry about: an 
interface and the related name.

> I guess I can only point at the rationales in 
> <http://docs.repoze.org/bfg/1.1/designdefense.html#bfg-uses-the-zope-component-architecture-zca>

Yep, and I agree with these.

>> Off the top of my head, another way to think of this *might* be to say 
>> that the 'dict access' is basically looking up a *named* utility 
>> providing a very generic marker interface, e.g. 
>> zope.component.interfaces.IUtility or even just 
>> zope.interface.Interface. That way reg['foo'] == getUtility(IUtility, 
>> name='foo'). Obviously, assignment would register in the same way.
>>
>> I'm not sure it's "better", though. :)
> 
> That would also be fine, and it would normalize things a bit, although the 
> implementation would be harder and it would result in slower lookups.  But if 
> it made folks feel better than inheriting from dict, I'd be +1 on it.

I think it would be nicer, because we could tell a story like this:

  - if you just want a place to store things by name...
  - ... which can be overridden at runtime or customised with local 
components ...
  - ... and you don't care too much about the notion of an interface ...
  - ... then here's the ZCA way to look up a component by name only

To register:

   reg = getSiteManager()
   reg['rootfactory'] = MyRoot()

To retrieve:

   reg['rootfactory']

To delete:

   del reg['rootfactory']


The equivalent ideas would be:

   reg.registerUtility(MyRoot(), provides=Interface, name='rootfactory')
   getUtility(Interface, name='rootfactory')
   reg.unregisterUtility(provides=Interface, name='rootfactory')

Although I suspect we want a marker interface that's a bit more specific 
than just 'Interface' since we already have some things that register 
interfaces as utility, I think. So maybe:

   class IAnonymousUtility(Interface):
       pass

Martin

-- 
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book



More information about the Zope-Dev mailing list