annotate base/stealth-mixins.lisp @ 252:b518b9f904e3

add stealth-mixin code from Strandh et al. (2007).
author Jamie Forth <j.forth@gold.ac.uk>
date Thu, 24 Feb 2011 11:23:18 +0000
parents
children
rev   line source
j@252 1 (in-package #:amuse)
j@252 2
j@252 3 ;;;=====================================================================
j@252 4 ;;; Taken from: Strandh, R., Hamer, J., and Baumann, G., (2007). Using
j@252 5 ;;; Stealth Mixins to Achieve Modularity. In Proceedings of the 2007
j@252 6 ;;; Australian Software Engineering Conference (ASWEC'07).
j@252 7 ;;; =====================================================================
j@252 8
j@252 9 (defvar *stealth-mixins* (make-hash-table))
j@252 10
j@252 11 (defmacro class-stealth-mixins (class)
j@252 12 `(gethash ,class *stealth-mixins*))
j@252 13
j@252 14 (defmacro define-stealth-mixin (name super-classes victim-class
j@252 15 &rest for-defclass)
j@252 16 "Like DEFCLASS but adds the newly defined class to the super classes
j@252 17 of `victim−class'."
j@252 18 `(progn
j@252 19 ;; First define the class we talk about
j@252 20 (defclass ,name ,super-classes ,@for-defclass)
j@252 21 ;; Add the class to the mixins of the victim
j@252 22 (sb-mop:ensure-class
j@252 23 ',victim-class
j@252 24 :direct-superclasses (adjoin ',name
j@252 25 (and (find-class ',victim-class nil)
j@252 26 (sb-mop:class-direct-superclasses
j@252 27 (find-class ',victim-class)))
j@252 28 :test #'class-equalp))
j@252 29 ;; Register it as a new mixin for the victim class
j@252 30 (pushnew ',name (class-stealth-mixins ',victim-class))
j@252 31 ;; When one wants to [re] define the victim class the new mixin
j@252 32 ;; should be present too . We do this by `patching' ensure−class:
j@252 33 (defmethod sb-mop:ensure-class-using-class :around
j@252 34 (class (name (eql ',victim-class)) &rest arguments
j@252 35 &key (direct-superclasses nil direct-superclasses-p)
j@252 36 &allow-other-keys)
j@252 37 (cond (direct-superclasses-p
j@252 38 ;; Silently modify the super classes to include our new
j@252 39 ;; mixin.
j@252 40 (dolist (k (class-stealth-mixins name))
j@252 41 (pushnew k direct-superclasses
j@252 42 :test #'class-equalp))
j@252 43 (apply #'call-next-method class name
j@252 44 :direct-superclasses direct-superclasses
j@252 45 arguments))
j@252 46 (t
j@252 47 (call-next-method))))
j@252 48 ',name))
j@252 49
j@252 50 ;; The `direct−superclasses' argument to ensure−class is a list of
j@252 51 ;; either classes or their names. Since we want to avoid duplicates,
j@252 52 ;; we need an appropriate equivalence predicate:
j@252 53 (defun class-equalp (c1 c2)
j@252 54 (when (symbolp c1) (setf c1 (find-class c1)))
j@252 55 (when (symbolp c2) (setf c2 (find-class c2)))
j@252 56 (eq c1 c2))