[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