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