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

Phillip J. Eby pje at telecommunity.com
Thu Jul 15 13:03:01 EDT 2004

At 09:43 AM 7/15/04 -0700, Dominikus Herzberg wrote:
>What I didn't really get was the part about AOP and generic functions and
>multiple dispatch, respectively. Is it that you understand generic functions
>as some sort of replacement or substitute for AOP? (You referred to a web
>page and AspectJ.) I don't clearly see the relation. Could you help me

Sorry if that was unclear.  The parallel I drew between CLOS generic 
functions and AspectJ is that AspectJ does AOP by way of "advice", which is 
generally in terms of "before, after, and around".  "Before advice" is code 
that runs before something, after runs after, and "around" has a chance to 
call the old version of the code, after modifying parameters or before 
modifying the return result.  (Or can replace it altogether.)

As it happens, CLOS-style generic functions also offer "before", "after", 
and "around" *methods*, which are basically the same thing.  (One imagines 
that the AspectJ folks took their inspiration from CLOS.)  The principal 
difference between CLOS and AspectJ in this respect is that AspectJ has a 
general-purpose language for identifying points in "oblivious" code (i.e. 
code that was not written with AspectJ in mind) where these "advice" 
methods can be applied.

However, if one programs with CLOS, then implicitly one may implement 
AspectJ-like advice anywhere, because any method in CLOS is inherently 
"advisable" in this way.

Thus, by implementing CLOS-style method combination for generic functions 
in the new generic function library, we gain all the benefits of these 
types of "advice" wherever we use generic functions.

As a simple example, consider non-functional aspects such as timing or 
logging.  If a particular program function is implemented as a generic 
function, we can wrap timing or logging code around it like this:

     [around("some condition describing when this should apply")]
     def some_function(...):
         start = time.clock()
         retval = next_method(...)
         end = time.clock()
         print "Took", end-start
         return retval

Of course, rather than hand code lots of timing wrappers like this, we'd 
implement a higher-order function that, given a generic function, a 
condition, and a function to call with the timing info, would automatically 
do the wrapping.  Something like 'time_function(some_func,condition,callback)'.

Anyway, timing, caching/memoization, logging, tracing, persistence, and 
various other non-functional aspects can be implemented in this way.  While 
the basic mechanism isn't quite as broad as AspectJ, and can't be applied 
to truly "oblivious" code, I believe it is "close enough" to be sufficient 
AOP for our purposes, and easier to use than PEAK's current AOP 
implementation for these types of aspects.

More information about the PEAK mailing list