Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sdd.hp.com!news.cs.indiana.edu!ux1.cso.uiuc.edu!midway!midway.uchicago.edu!berger From: berger@tartarus.uchicago.edu (Jeff Berger) Newsgroups: comp.lang.clos Subject: Procedural attachment Message-ID: Date: 12 Jun 91 03:04:43 GMT Sender: news@midway.uchicago.edu (NewsMistress) Distribution: comp Organization: University of Chicago Computer Science Lines: 132 The June issue of AI Expert contains an article titled "Frames in CLOS", by J. Veitch. One of the topics covered is how to define CLOS classes so that slot values for CLOS instances can be retrieved from a data base as needed rather than being actually present in memory. That's close enough to a problem I'm trying to solve that I thought I could easily adapt the code to my purposes. I want calls of the form (slot-value instance201ofclass3 'slot2) to return (slot-value instance17ofclass1 'slot4). The two classes have minimally overlapping slots. I want to be sure that changes in value for a quantity stored in the instance of one class are automatically reflected in the value of the same quantity in another instance of a different class. While I'm a beginner at CLOS, the code fragments given in the article, although marred by typo's and minor bugs, (AI Expert needs a good proof-reader) seemed clear enough to convince me I could make an easy adaptation. The trick is to write methods for SLOT-VALUE-USING-CLASS which apply to a user-defined metaclass. To wit: #| FILENAME: ORGAN-TOLERANCE-CLASS.CL Code for the definition of the class ORGAN-TOLERANCE. One slot in the class is read from an ASSUMPTION class object. |# (defclass META-ORGAN-TOLERANCE (clos:standard-class) ()) ; The user-defined metaclass (defclass ORGAN-TOLERANCE () ; instances of this class should get the ; value for the LIMIT slot from the VALUE ; slot a (particular) instance of the ASSUMPTION ; class (defined elsewhere). ((organ :initarg :organ :accessor :organ) (limit :reader :limit :allocation :assumption) (fraction :accessor :fraction :initarg :fraction :initform 1.0)) (:metaclass meta-organ-tolerance)) (defmethod SLOT-VALUE-USING-CLASS ((class meta-organ-tolerance) instance slot-name) (let ((slot (do ((x (clos:class-slots class) (cdr x))) ((or (null x) (eq slot-name (clos:slot-definition-name (car x)))) (car x))))) (if (and slot (eq (clos:slot-definition-allocation slot) :assumption)) (get-tolerance-from-assumption instance) (call-next-method)))) (defun GET-TOLERANCE-FROM-ASSUMPTION ; This pulls the desired value ; from an instance of the ASSUMPTION ; class retrieved by ; GET-CURRENT-ASSUMPTION. (organtolerance &aux (organ (slot-value organtolerance :organ)) ; gets a symbol (tname (symbol-catenate organ 'tolerance)) ; catenates the symbols (assumption (get-current-assumption tname))) (if assumption (slot-value assumption 'value) nil)) According to the article, making the allocation of the LIMIT slot an option unknown to CLOS (i.e., :ASSUMPTION) will suppress slot allocation. Unfortunately, when I attempt to create an instance of the class ORGANTOLERANCE, I get an error. (SETQ ILUNGT (MAKE-INSTANCE 'ORGAN-TOLERANCE :ORGAN 'IPSILATERAL-LUNG :FRACTION 0.9)) Error: The slot LIMIT is missing from the object # of class # Looking at the execution stack, it seems that SHARED-INITIALIZE is checking whether or not the slots of the object it is initializing are unbound and is discovering that the slot is missing. I tried writing a method to kludge over the situation: (defmethod SLOT-BOUNDP-USING-CLASS ((class organ-tolerance) object slot-name) (or (eq 'limit slot-name) (call-next-method))) But the method is never found. Here's part of the stack: Evaluation stack: ->call to ERROR required arg: EXCL::DATUM = "The slot ~S is missing from the object ~S of class ~S" &rest EXCL::ARGUMENTS = (LIMIT # #) call to (CLOS:METHOD SLOT-MISSING (T T T ...)) required arg: CLOS:CLASS = # required arg: CLOS::OBJECT = # required arg: CLOS::SLOT-NAME = LIMIT required arg: CLOS::OPERATION = SLOT-BOUNDP optional arg: CLOS::NEW-VALUE = 0.9 call to CLOS::SLOT-BOUNDP--STANDARD-CLASS required arg: CLOS::OBJECT = # required arg: CLOS::SLOT-NAME = LIMIT call to (CLOS:METHOD CLOS:SLOT-BOUNDP-USING-CLASS (CLOS:STANDARD-CLASS CLOS:STANDARD-OBJECT T)) required arg: CLOS:CLASS = # required arg: CLOS::OBJECT = # required arg: CLOS::SLOT-NAME = LIMIT call to (CLOS:METHOD SLOT-BOUNDP (CLOS:STANDARD-OBJECT T)) required arg: CLOS::INSTANCE = # required arg: CLOS::SLOT-NAME = LIMIT call to (CLOS:METHOD SHARED-INITIALIZE (CLOS:STANDARD-OBJECT T)) required arg: CLOS::INSTANCE = # required arg: CLOS::SLOT-NAMES = T &rest CLOS::INITARGS = (:ORGAN IPSILATERAL-LUNG :FRACTION 0.9) I know, this example exhibits lots of quick and dirty hacks, BUT besides that, what am I doing wrong? P.S. To Mr. Veitch (if he happens to see this). I probably should have written to you at AI EXPERT about this. But I crave instant answers. -- Jeff Berger |USmail: Ryerson 256 berger@tartarus.uchicago.edu | 1100 East 58th Street (312) 702-8584 | Chicago, IL 60637