[Persistence-sig] A simple Observation API

Phillip J. Eby pje@telecommunity.com
Mon, 29 Jul 2002 17:37:45 -0400


At 05:18 PM 7/29/02 -0400, Guido van Rossum wrote:
>Some questions about Phillip's Observable protocol.  Wby does it have
>to be so complicated?  E.g. if you have to do something special for
>method that touches an attribute without doing a setattr operation on
>it, why not have the magic be inside that method rather than declare a
>wrapper?  (The wrapper looks like it is much more expensive than
>another way of flagging a change would be.)

It's only for event compression, otherwise putting a simple flag operation
in the method would indeed be more lightweight.  Of course, I'm pretty sure
I could write a bytecode-hacking version that would recode the underlying
method to include the necessary wrapping code around its body, making it
just as fast as putting the code inline.  But I didn't want to put that
much effort into an example.  :)


>What exactly is the point of collapsing multiple setattr() ops
>together?  Just performance?  Or is there a semantic reason?  If just
>performance, where is the time going that you're trying to save?

Semantics plus performance.  The semantic part is that some "database"
systems (e.g. LDAP) inherently don't support transactions, AND must receive
a semantically valid set of attributes in a single update operation.  I may
be overgeneralizing this aspect, however.

The performance save is for situations like Tim Peters' distributed cache
example.  If a change notification is going to cause network traffic, it
would be a good idea to minimize the number of such notifications.  It's a
common situation (IMHO) to change multiple attributes in a set of related
methods, so this supports that scenario while ensuring a minimal set of
update events are issued.


>What's the use case for declaring a method as "touches an attribute
>but that change should be ignored"?  (If it's only __init__, a
>lighter-weight mechanism might be sufficient.)

I discovered the __init__ issue when I went to write the example code, and
adding an ignore list seemed like the simplest way to solve it quickly
without adding a metaclass or something else special to handle __init__.
Also, I know I've frequently written classes which do the bulk of their
attribute setup in methods other than __init__, and imagine others do as
well.  These days I use PEAK attribute binding descriptors that
automatically initialize attributes on first-use, instead, but I wrote the
Observable example assuming "plain-jane", "mainstream" Python with no
special metaclasses or the like.

In general, as to the features of the API, I wrote this mostly based on the
use cases that other folks had, although I'm certainly not against having
event compression.  :)  My own requirements in the API are only the
changeable "get" hook, and that notification of writes takes place after
the modifications.

The idea of using method wrappers to incorporate the metadata about what
attributes are modified, was an attempt to help mask implementation details
from the "naive" user.  It seemed to me a less invasive form of "dead
chicken waving", and also allowed for alternative implementation strategies
for the observable's internal mechanism.