Hooks, aspect-oriented programming, and design by contract

Alex Martelli aleax at aleax.it
Wed Jan 23 14:11:27 CET 2002


"Pedro Rodriguez" <pedro_rodriguez at club-internet.fr> wrote in message
news:pan.2002.01.23.12.06.54.615677.1794 at club-internet.fr...
    ...
> - metaclass is used to define class templates so that all classes exhibit
>   the same design (like the example in descintro on autosuper, autoprop,
>   or the example posted on post/pre/invariant conditions).

Not *ALL* classes, but, one or more classes belonging to that metaclass.

> - when you define a class relying on a metaclass, what the metaclass does
>   for your class must be known to the user of the class (say it is part
>   of its contract)

Although most often the metaclass's semantics will be known to "users",
this is not necessarily a requirement, for some definition of "user".  In
other words, "must" is too strong a word here.

One simple (maybe even silly) example: I can write a metaclass that
does substantially nothing different from builtin type (the normal
metaclass of all except classic classes) EXCEPT emit a message upon
each instantiation:

import types

class mymeta(type):
    def __call__(self, *arg, **kw):
        print "Creating instance of", self.__name__
        return type.__call__(self, *arg, **kw)

def makeaclassandafewinstances():
    class justaclass:
        def __del__(self): print "destroying an instance"
    a = justaclass()
    b = justaclass()

__metaclass__ = type
makeaclassandafewinstances()
__metaclass__ = mymeta
makeaclassandafewinstances()

The "user" who sets the global __metaclass__ may or may not have
to know in details the semantics of mymeta -- maybe he or she
just knows that certain nice things happen when it's set that
way.  Even less does the "user" who authors justaclass "have to"
know about the workings of mymeta; indeed, class justaclass may
well have been authored well before mymeta was even conceived.

Many metaclasses will prove "invasive" in the sense that the
classes instantiating them need to be authored and/or used in
full knowledge of the metaclass's semantics, but that is by
no means necessarily the case.  A metaclass may be coded to
be "semantically transparent" (behave the same as some other
metaclass from the point of view of class implementors and/or
from that of class users) but provide extra "instrumentation"
(e.g. for tracing, profiling, dispatching events to arbitrary
external observers, ...).


> - aspect is to factorize a behaviour at some points of the application
>   (near methods entry/exit point)

Well, not _inside_ methods themselves (except maybe when they
call other methods), for sure.

> - it may be done to capture a design feature but this is not mandatory
> - an aspect is not part of the 'contract' of a class since a class is
>   not aware of the aspects that have been put on it
> - an aspect may be part of the 'contract' of an overall design

May or may not, yes.


> Technically, both will involve class modification (by method wrapping,
> attribute addition).

I find it strange to say that a metaclass "involves class modification";
that's the same as saying that a class "involves instance modification",
since the class-metaclass relationship is that of instance-class too.  A
metaclass _builds_ a class (in just the same sense as a class _builds_
an instance), defines the class's behavior (ditto).

You may think of that building and defining as "modifying" when relating
two metaclasses to each other -- metaclass A 'modifies' metaclass B in
that the classes it builds and defines may do "the same as those built
and defined by B, except ..."; when implementing A, you may well take
advantage of inheritance from B and override some minor part (possibly
delegating also to the base-metaclass B).  Since there are "default
metaclasses" (types.ClassType, alas non-inheritable; and builtin type
itself), the "modification" framing of the issue may sound more
reasonable than it would be for classes and instances, but it may
easily turn out to be a too-restrictive framing in some cases.

When an aspect *augments* an object, you can surely say it "modifies"
that object.  However, I see no reason in Python why said object
should necessarily be a class, at least in Python and other languages
allowing independent alterations to instances (I think Ruby does that,
and I wonder if Aspect/R supports only class-level, or also instance
level, aspecting/augmenting).


> When will these modifications take place :
> - dynamically and retroactively : no (too much tracking)

Tracking of what?  An instance always 'tracks' its class: if you
modify the class, all existing instances will just 'magically'
follow suit.  No 'tracking' needed.

> - temporary : no (will need a registering scheme, except for debugging
>   purpose won't be of any interest, and even for debugging there are
>   simpler way to activate/deactivate it)

Aspecting is about separation of concerns.  If a concern being
separated this way has temporary applicability in the course of
a long-running application, dynamical and temporary augmentation
seems perfectly feasible and useful to me.

> - static : yes, at startup for aspects, at class/instance creation for
>   metaclasses. This is part of the design of the application.

That may be more effective when applicable, reducing overhead.  But
(for aspecting in general) it's restrictive to _constrain_ it thus.

Metaclasses (I believe, and I'd love to be proved wrong!) do
intrinsically imply the constraint of being applied at class creation
time (not switchable for a given class object, I think).  When
something more dynamic is needed, then, metaclasses are not the
appropriate technology.  But when the static applicability is
not a concern, using the "right" metaclass for class creation may
give wider purview and greater efficiency than using a metaclass
that is not considered fully satisfactory and then augmenting by
other means (operating on the class object as created).


> Should C extensions provide such a mechanism ? No, keep the extension
> simple, and provide a Python wrapper will can be overriden.

C extensions provide further flexibility yet (they can do things
that no Python-coded metaclass can, such as allocating some huge,
arbitrary blob of memory), and more importantly further efficiency
if the speed of Python-coded metaclasses should be a concern
(admittedly unlikely).  The price, of course, is always pretty
steep.


> Should aspects be based on metaclasses ? No, they don't have the same
> purpose. Maybe there could be some interest to define a metaclass to
> help tracking Pointcuts or setting advices, but I don't think this is
> mandatory.

I don't think a metaclass is 'mandatory' for most of the uses a
metaclass can be put to: clever and devious use of __getattribute__
etc can often substitute.  That's not to say that metaclasses is
not *most appropriate*, whenever it lets you do things in a more
straightforward and effective fashion.  The set of needs covered
by metaclasses and other Python mechanisms overlap without fully
coinciding (so, "they don't have the same purpose" -- not exactly
the SAME one).  But metaclasses may well be just the right
technology for implementing (or forming a part of the implementation
of) many kinds of manipulations, including many of those covered
by aspect oriented programming.


Alex






More information about the Python-list mailing list