[PEAK] Persistence styles, MDA, AOP, PyProtocols, and PEAK

Robert Brewer fumanchu at amor.org
Wed Jul 7 11:31:01 EDT 2004

Phillip J. Eby wrote:
> What good does that do?  Well, think about storage.  Suppose 
> you defined a 
> generic function like this:
>      def save_to(ob, db):
>          ...

Is this to support saving an object to potentially multiple stores?
Otherwise, I can't see the reason to make this a generic function, as
opposed to a method of the db class. In other words, what does this buy
you over:

class MySQLManager(SQLManager):
    def save(self, ob):

...or is it simply having a hammer in your hand? ;)

> And what if you could define implementations of this function 
> for different 
> combinations of object type and database type?  Maybe something like:
>      [when("isinstance(ob,Invoice) and isinstance(db,XMLDocument)")]
>      def save_to(ob,db):
>          # code to write out invoice as XML
>      [when("isinstance(db,PickleFile)")]
>      def save_to(ob,db):
>          # code to write out arbitrary object as a pickle
> Doesn't this look a *lot* easier to you than writing DM classes?

hmmm... not for the PickleFile, at least. ;) I see the modularity being
a big issue; in what module or layer would the first code example be
placed? Invoice.py? XMLDocument.py? App/Model.py?

> Which means that if you don't need, say, the pickle use case,
> you could just not import that module, which means that
> branch of our "virtual if statement" simply wouldn't exist,
> thus consuming no excess memory or CPU time.  So, they can be
> "write anywhere, run any time".  Now that's what I call
> "modular separation of concerns".  :)

I've always found object composition (via dynamic imports at config-read
time) to solve this quite well. I guess it depends again on where you
see your "save_to" function being defined and invoked.

> In addition to the functionality proof-of-concept, I've also got a 
> proof-of-concept Python expression parser (that so far 
> handles everything 
> but list comprehensions and lambdas) for what's needed to 
> implement the 
> fancy 'when/before/after()' API.  And there's a 
> proof-of-concept for the 
> "function decorator syntax" as well.

FWIW, I handle when/before/after using triggers within attribute

> Further, the in-CVS prototype dispatcher automatically
> recognizes common subexpressions between rules, so 
> that e.g. 'target.isDrinkable()' will get called only *once* 
> per call to the generic function, even if the expression
> appears in dozens of rules. Also, the prototype dispatcher
> automatically checks "more discriminating" tests first.  

Nice bit of coding, that. :)

> I haven't narrowed these down 100%, but here's what I think 
> so far.  The query language is probably going to end up
> being Python, specifically list or generator comprehensions, e.g.:
>      [(invoice,invoice.customer) for invoice in Invoices
>       if status=="pastdue"]
> However, these will be specified as *strings*.

Cheater. ;) Show an example using a date which has been obtained from
the end-user.

"""[(invoice, invoice.customer) for invoice in Invoices
if status == %s and duedate > %s""" % (coerce(stat), coerce(due))

Robert Brewer
Amor Ministries
fumanchu at amor.org

More information about the PEAK mailing list