[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
>here?
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