[Zope3-dev] practice and theory: event service and connotations of "implementing an interface"

Gary Poster gary@zope.com
Thu, 19 Dec 2002 16:03:40 -0500


First theory, then a divider, then practice.

Through subclassing, the global event service claims to implement 
subscribable, yet raises a NotImplementedError when one of its methods, 
subscribe, is called.

I understand the practical reasoning for this, and am trying with Steve 
and Casey to come up with a solution for the practical issues (see 
second half below for a new proposal).

But more theoretically, can an object truly claim to implement an 
interface merely by having the method name, even if it does not live up 
to the descriptive contract?  This seems like a bad precedent.

If a method in an interface is overridden in a subclassed interface, it 
seems to me that the method must either be limited in a way explicitly 
permitted by the super interface, or be increased in its functionality 
while still allowing the original behavior.

Thoughts?  If I'm right, this seems like a style guide entry (yes, yes, 
I'll do it :-); if I'm wrong, it might be good to get the correct 
version in there anyway.

------------------

More practically, speaking about the event service, I am reneging on my 
approval of the design described above and the "globalSubscribe" method.

Instead, I would like to make the following interface changes for the 
goals we have identified (namely, let wrapped objects subscribe easily 
in a wrapped manner, hopefully being able to take advantage of the hubid 
service; and let it be impossible for them to subscribe to the global 
service).

The description of Zope.Event.ISubscribable.subscribe will be as follows 
(the only change is in the second paragraph):

     def subscribe(subscriber, event_type=IEvent, filter=None):
         """Add subscriber to the list of subscribers for the channel.

         subscriber must implement ISubscriber, or will raise a
         SubscriptionError.  Based on implementation or subclassed
         interface, subscribable may also raise a SubscriptionError if
         the subscriber does not meet other criteria.

         event_type, if supplied, is the event interface
         about which subscriber should be notified, and must implement
         IEvent.  The subscriber will be notified of all events of this
         event_type and of subclasses of this event_type.
         The default value, IEvent, as the parent type, is effectively a
         single catch-all event type that will pass all event types to
         the subscriber.

         filter, if supplied, must implement IEventFilter; subscriber
         will be notified of events only if they pass.

         A subscriber may subscribe more than once, even if it has
         already been subscribed with the same event type and
         filter.  In this case the subscriber will receive multiple
         calls to its notify method.

         If the subscriber implements ISubscriptionAware, this function
         will call the subscriber's subscribedTo method.
         """

The GlobalEventService will move to the newly-made home of 
Zope.App.Event, proposed by Steve.  The 
Zope.App.Event.GlobalEventService.IGlobalEventService will inherit from 
Zope.Event.IEventService, which inherits from Zope.Event.ISubscribable. 
  It will override the subscribe method as follows:

     def subscribe(subscriber, event_type=IEvent, filter=None):
         """As Zope.Event.ISubscribable.  Will raise a SubscriptionError
         if the subscriber is wrapped.
         """

The LocalEventService will remain in 
Zope.App.OFS.Services.LocalEventService (soon to be zope.app.ofs.event, 
of course).  The 
Zope.App.OFS.Services.LocalEventService.LocalEventService.ILocalEventService 
will override the subscribe method as follows:

     def subscribe(subscriber, event_type=IEvent, filter=None):
         """As Zope.Event.ISubscribable.  Will raise a SubscriptionError
         if the subscriber is not wrapped.  Storage of wrapped object is
         implementation specific, but must always call subscriber's
         notify in wrapped context"""

The built in implementation will always try first to store the object 
via the hubid service, and failing that will use an absolute path.

Gary