[Zope3-dev] Re: practice and theory: event service and connotations of "implementing
an interface"
Steve Alexander
steve@cat-box.net
Fri, 20 Dec 2002 09:08:00 +0000
> 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.
I'll excplain this at more length below. Basically, you're right in this:
> 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?
However, that is not the case with a method raising an exception.
Raising an exception is always a valid alternative to doing the work
requested.
If you'd said:
Can an object truly claim to implement an interface if it always
raises an exception in response to a calling a method given in the
interface?
Then the answer is "yes".
Longer explanation:
When a component advertises an operation in an interface, it does not
guarentee that the operation will always succeed. Often, whether or not
the operation will be successful depends on the internal state of the
object being operated upon.
Anything can raise an exception.
In the case of the GlobalEventService, the 'subscribe' operation will
always be unsuccessful. I'm fine with this, and I think it is a valid
fulfilment of the interface.
Now, if you called 'subscribe' on an ISubscribable and it did something
entirely different, like created a whole bunch of objects, or erased
your hard disk, or aborted all http connections, (add other outrageous
things here), and still didn't subscribe the client as requested, then
that would not be a valid fulfilment of the interface
I could make an ICreateBunchOfObjectsSubscribabale interface that would
either subscribe and create a whole bunch of objects, or raise an
exception and not subscribe and not create any objects.
Implementing an interface says to clients "You may call this method,
which will be understood as this kind of request, with these arguments".
Like all requests, a request may be declined.
You could write an interface that describes a request that can never be
declined, but that would be a pretty special interface.
In the case of the GlobalEventService, it is a fault in the overall
configuration of your application if you try to subscribe a local object
to it. Raising an exception is quite appropriate here.
> 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.
> """
That won't do. A subscriber doesn't have to be wrapped to be a local
object. Only global objects may subscribe to the global event service.
An object is either local or global.
At the sprintathon, I talked at some length with Jim about the
GlobalEventService. Making it have a globalSubscribe method was the best
we could come up with. I'm open to other ideas, though.
Here are the constraints:
* There must be no way for a local object inadvertantly to subscribe to
the global event service.
* The global event service must implement the interface declared for the
"Events" serviceType.
Also, there is no obvious way to distinguish between a local object and
a global object by inspecting the object.
The global event service *could* implement 'subscribe' by trying to get
a location for the subscriber and failing if it can get a location. But,
this still doesn't stop a local subscriber that is not properly wrapped
(for whatever reason) from subscribing globally.
Having 'subscribe' raise an exception, and having a separate
globalSubscribe method is easy to understand, simple to implement, and
has no loop-holes.
> The built in implementation will always try first to store the object
> via the hubid service, and failing that will use an absolute path.
This is too implicit. I think the local event service should subscribe
by path by default with the 'subscribe' method. It should be easy to
subscribe by hubId, but it should be something explicit.
One reason for this is that it is important to know if you have
successfully subscribed by hubId. This allows you to move your
subscriber around without changing your subscription. The implicit
fall-back you describe doesn't give this feedback.
--
Steve Alexander