Hooks, aspect-oriented programming, and design by contract

Pedro Rodriguez pedro_rodriguez at club-internet.fr
Wed Jan 23 15:59:49 EST 2002


"Alex Martelli" <aleax at aleax.it> wrote:

> "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.

Yes.


> 
>> - 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.
> 

I expect that someone defining a metaclass, will use it to some purpose
for future classes that will be created from it. And what it adds to 
classes concerns developers that will use or subclass them. 
The mechanic of the metaclass semantics are "irrelevant" to those users, 
its side effects yes. If it has no side effect for those developper, 
the metaclass shouldn't be used, an aspect should be considered (I am
certainly twisting the interpretation of metaclass/aspect to fit my 
feelings, yes ;)


> 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.

I get the feeling that using the __metaclass__ setting for its side
effects on the semantic of class declaration is not the right thing. I
think that explicitness is recommended. I think, picking your example,
that an aspect will suit much better (not that I am saying that your
example will be what you actually recommend to do).

class PrintAspect(Aspect):
    def print(self, ..., *args, **kwargs):
        print "Creating instance of", args[0].__class__.__name__

aspect = PrintAspect()
aspect.wrap_before("print", justaclass, "__init__") # explicitly


>  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, ...).
> 

But, IMHO, not the best fitted, because you'll have to set __metaclass__
explicitly for each class, or as a global as in your example. Too
intrusive for instrumentation.


> 
>> - 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).
> 

Agreed. (maybe I am the one being modified by metaclasses ;)


> 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).
> 
Posted a remark about this. In python, this could concern : class,
instances, modules.

> 
>> 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.

Wrong thinking of my part. I thought that if you overload a method in
a class, already existing instances won't get the modification.
On the other hand, if you override a method in an instance.


> 
>> - 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.

Can't think of a case of this will be required ? Lack of experience in
this area.


> 
>> - 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.
>

Maybe it's me. I don't think I will be encline to modify methods while
the application runs.

 
> 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.

I think I agree with you.


> 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).

Sorry you lost me here.


> 
> 
>> 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.
> 

I still find __metaclass__ to intrusive to implement aspects. 
Time may tell.


> 
> Alex
> 
> 
> 


Thanks for the posting,
-- 

Pedro





More information about the Python-list mailing list