[rjain-utils-cvs] CVS prototypes

rjain rjain at common-lisp.net
Tue Nov 24 10:43:30 UTC 2009


Update of /project/rjain-utils/cvsroot/prototypes
In directory cl-net:/tmp/cvs-serv9460

Modified Files:
	prototypes.lisp 
Log Message:
documentation
robustness
initiarg processing during instance creation


--- /project/rjain-utils/cvsroot/prototypes/prototypes.lisp	2009/11/24 10:40:13	1.4
+++ /project/rjain-utils/cvsroot/prototypes/prototypes.lisp	2009/11/24 10:43:30	1.5
@@ -8,29 +8,65 @@
 
 (in-package :prototypes)
 
+;;;;
+;;;; PROTOTYPE-OBJECT
+;;;;
 
 (defclass prototype-object ()
   ((%delegates :initarg :delegates
                :reader prototype-delegates
                :writer %set-prototype-delegates
-               :initform nil)))
+               :initform nil))
+  (:documentation "The root of the prototype hierarchy. Instantiate this
+  class to create a new prototype, possibly initializing it with
+  a :DELEGATES argument to provide a list of other prototype instances
+  that slots will be inherited from."))
+
+(defgeneric prototype-add-delegate (object delegate)
+  ;; TODO: test case
+  ;; Maybe indicate whether delegate was already there?
+  (:documentation "Adds a DELEGATE to the end of OBJECT's delegates, if
+  it is not already there. Returns no values.")
+  (:method ((object prototype-object) (delegate prototype-object))
+    (if (prototype-delegates object)
+        (loop for tail on (prototype-delegates object)
+           until (eql delegate (car tail))
+           finally (setf (cdr tail) (list delegate)))
+        (%set-prototype-delegates (list delegate) object))
+    (values)))
+
+(defgeneric prototype-remove-delegate (object delegate)
+  ;; TODO: test case
+  ;; Maybe indicate whether delegate was actually found?
+  (:documentation "Removes DELEGATE from OBJECT's delegates, if it is
+  there. Returns no values.")
+  (:method ((object prototype-object) (delegate prototype-object))
+    (%set-prototype-delegates (delete delegate (prototype-delegates object))
+                              object)
+    (values)))
+
+;;;;
+;;;; Utility for memoization of searches
+;;;;
 
-(defmethod prototype-add-delegate ((object prototype-object) (delegate prototype-object))
-  (loop for tail on (prototype-delegates object)
-       until (eql object (car tail))
-       finally (setf (cdr tail) (list delegate))))
-
-(defmethod prototype-remove-delegate ((object prototype-object) (delegate prototype-object))
-  (%set-prototype-delegates object (delete delegate (prototype-delegates object))))
+(defun symbolicate (x) 
+  (make-symbol (write-to-string x :escape nil)))
 
 (defun memoize-method-result (generic-function specializers result)
-  (add-method generic-function
-              (make-instance 'standard-method
-                             :lambda-list (mapcar (lambda (x) 
-                                                    (make-symbol (write-to-string x :escape nil)))
-                                                  specializers)
-                             :specializers specializers
-                             :function (constantly result))))
+  (restart-case
+      (add-method generic-function
+                  (make-instance 'standard-method
+                                 :lambda-list (mapcar #'symbolicate
+                                                      specializers)
+                                 :specializers specializers
+                                 :function (constantly result)))
+    (disable-memoization ()
+      :report "Disable memoization and continue."
+      (setf (symbol-function 'memoize-method-result) (constantly nil)))))
+
+;;;;
+;;;; Prototype backend class search and generation
+;;;;
 
 (defgeneric prototype-find-subclass (prototype slot-name))
 
@@ -55,6 +91,13 @@
   (or (prototype-find-subclass class slot-name)
       (prototype-subclass class slot-name)))
 
+;;;;
+;;;; Additional functionality needed for prototype object manipulation
+;;;; beyond what CLOS gives us for free
+;;;;
+
+;;; TODO: Delegate down a linearized precedence list. Maybe offer both
+;;; CLOS and C3 linearization algorithms.
 (macrolet ((reader-delegation (operation)
              `(defmethod slot-missing (class (object prototype-object)
                                        slot-name (operation (eql ',operation))
@@ -63,6 +106,12 @@
                 (dolist (delegate (prototype-delegates object)
                          (call-next-method))
                   (ignore-errors
+                    ;; if OPERATION succeeds on the delegate, RETURN
+                    ;; that result from our loop, otherwise it will
+                    ;; error and continue on to the next delegate, via
+                    ;; IGNORE-ERRORS. If no delegates are left, it will
+                    ;; call the default method which signals a
+                    ;; slot-missing error.
                     (return (,operation delegate slot-name)))))))
   (reader-delegation slot-value)
   (reader-delegation slot-boundp))
@@ -76,8 +125,21 @@
   (writer-subclassing setf slot-name new-value)
   (writer-subclassing slot-makunbound))
 
-(defmethod make-instance ((prototype prototype-object) &key)
-  (make-instance 'prototype-object :delegates (list prototype)))
+;;;;
+;;;; Shortcut for single-inheritance
+;;;;
+
+(defmethod make-instance ((prototype prototype-object) &rest initargs
+                          &key &allow-other-keys)
+  "Create a PROTOTYPE-OBJECT that delegates to the given PROTOTYPE."
+  (let ((object (make-instance 'prototype-object :delegates (list prototype))))
+    (loop for (slot-name value) on initargs by #'cddr
+       do (setf (slot-value object slot-name) value))
+    object))
+
+;;;;
+;;;; Subclassing of CLOS classes as prototype objects
+;;;;
 
 (defgeneric find-std-class-prototype (class))
 
@@ -101,16 +163,22 @@
   (or (find-std-class-prototype class)
       (make-std-class-prototype class)))
 
-(defgeneric make-prototype (class &key delegates))
-
-(defmethod make-prototype ((class-name symbol) &key delegates)
-  (make-prototype (find-class class-name) :delegates delegates))
-
-(defmethod make-prototype ((class standard-class) &key delegates)
-  (make-instance (ensure-std-class-prototype class)
-                 :delegates delegates))
+(defgeneric make-prototype (class &rest initargs
+                                  &key delegates &allow-other-keys)
+  (:documentation "Create a prototype instance that is an instance of
+  CLASS, initializing it with the given INITARGS, which may
+  include :DELEGATES to specify the instance's delegates."))
+
+(defmethod make-prototype ((class-name symbol) &rest initargs)
+  (apply #'make-prototype (find-class class-name) initargs))
+
+(defmethod make-prototype ((class standard-class) &rest initargs)
+  (apply #'make-instance (ensure-std-class-prototype class)
+         initargs))
 
+;;;;
 ;;;; TESTS
+;;;;
 
 (defparameter *1* (make-instance 'prototype-object))
 (setf (slot-value *1* 'x) 1)
@@ -174,4 +242,4 @@
 
 (assert (eql (slot-value *t* 'x) :t))
 (assert (eql (slot-value *3.t* 'x) 3))
-(assert (eql (slot-value *t.3* 'x) :t))
+(assert (eql (slot-value *t.3* 'x) :t)) ; The slot is class-allocated, remember!





More information about the Rjain-utils-cvs mailing list