[Zope3-dev] EventService, references, and subscription semantics

Shane Hathaway shane@zope.com
Mon, 25 Feb 2002 17:38:05 -0500


Steve Alexander wrote:
> Casey Duncan wrote:
> 
>>
>>
>>> Then, we still have the issue of what to use for references.
>>> We can use object references provided we're happy to only allow
>>> persistent objects to be passed to subscribe().
>>>
>>
>> This is the problem I tried to work on in my ExplicitObjectReferences 
>> proposal. The problem with using regular object references is that the 
>> subscriber looses its original context and the reference makes the 
>> object persist even if it is deleted from its original location.
>>
>> So unless these two things aren't an issue, I don't think object 
>> references will work for this. I will definitely not mind being wrong, 
>> however.
> 
> 
> I thinnk you're wrong :-)
> 
> The object references are only used in the EventService to keep a 
> collection of subscribers.

In a current project here at ZC we've stumbled onto an idea that neatly 
deals with the object reference problem: just encapsulate all references 
as objects.  When registering with the event service, register the 
reference object.   When the service fires the event, it first 
dereferences the reference.

In fact, in practice, references seem to be easier to work with than 
physical paths.  Here is a prototype interface:


class IReference (Interface):
     """Provides a way to find an object without necessarily keeping a
     strong reference."""

     def dereference(context):
         """Returns the referenced object."""


Here is a simple path-based implementation for Zope2:


class DereferenceError (Exception):
     """Could not resolve a reference"""


class ReferenceByPath(Persistent):
     """Provides a path-based reference to an object."""
     __implements__ = IReference

     def __init__(self, object):
         """Retains a reference to the target object."""
         self._path = object.getPhysicalPath()

     def dereference(self, context):
         """Returns the original object, wrapped in the specified
         context."""
         path = self._path
         try:
             return self.restrictedTraverse(path).__of__(context)
         except (AttributeError, KeyError):
             raise DereferenceError, path


The nice thing is you can encapsulate both strong and weak references 
this way.  The reference could hold an absolute path, a relative path, 
the object itself, a URL, a database query, etc.

Shane