1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4 ;;;; LISP-STAT Object System
7 ;;;; Simple CL implementation of the object system for Lisp-Stat (LSOS)
8 ;;;; as described in Tierney (1990).
10 ;;;; Copyright (c) 1991, by Luke Tierney. Permission is granted for
11 ;;;; unrestricted use.
16 ;;;; If your CL's handling of packages is compliant with CLtL, 2nd
17 ;;;; Edition (like Macintosh CL version 2), add the feature :CLtL2
18 ;;;; before loading or compiling this code.
20 ;;;; This implementation does not make use of CLOS. It can coexist
21 ;;;; with CLOS, but there are two name conflicts: slot-value and
22 ;;;; call-next-method. These two symbols are shadowed in the LSOS
23 ;;;; package and must be shadowed in any package that uses LSOS.
24 ;;;; Evaluating the function (lsos::use-lsos) from a package after
25 ;;;; loading this code shadows these two symbols and does a
26 ;;;; use-package for LSOS.
28 ;;;; The :compile-method method uses function-lambda-expression
29 ;;;; defined in CLtL, 2nd Edition. (This method is only needed if
30 ;;;; you want to force compilation of an interpreted method. It is
31 ;;;; not used by the compiler.)
33 ;;;; The efficiency of this code could be improved by low level
34 ;;;; coding of the dispatching functions send, call-method and
35 ;;;; call-next-method to avoid creating an argument list. Other
36 ;;;; efficiency improvements are possible as well, in particular
37 ;;;; by good use of declarations. It may also be possible to build
38 ;;;; a more efficient implementation using the CLOS metaclass
41 ;;;; There are a few minimal tools for experimenting with constraints
42 ;;;; in the code; they are marked by #+:constreinthooks. Sometime
43 ;;;; soon I hope to augment or replace these hooks with a CORAL-like
44 ;;;; constraint system (as used in GARNET).
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
57 (defpackage "LISP-STAT-OBJECT-SYSTEM"
58 (:nicknames
"LS-OBJECTS" "LSOS")
60 (:shadow
"CALL-NEXT-METHOD" "SLOT-VALUE"))
62 (in-package lisp-stat-object-system
))
66 (in-package 'lisp-stat-object-system
67 :nicknames
'(ls-objects lsos
)
70 (shadow '(call-next-method slot-value
)))
72 (export '(ls-object objectp
*object
* kind-of-p make-object
*message-hook
*
73 *set-slot-hook
* slot-value self send call-next-method call-method
74 defmeth defproto instance-slots proto-name
))
77 (shadowing-import (package-shadowing-symbols 'lisp-stat-object-system
))
78 (use-package 'lisp-stat-object-system
))
81 ;;;; Structure Implementation of Lisp-Stat Object System
84 (defvar *object-serial
* 0)
87 (:constructor make-object-structure
)
88 (:print-function print-object-structure
)
94 (serial (incf *object-serial
*)))
96 (defun print-object-structure (object stream depth
)
97 (send object
:print stream
))
99 (setf (documentation 'objectp
'function
)
101 Returns T if X is an object, NIL otherwise.")
103 (defvar *object
* (make-object-structure))
105 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
107 ;;;; Utility Functions
109 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
111 ;;;; special variable to hold current value of SELF
115 (if (not (objectp *self
*)) (error "not in a method"))
118 (defun has-duplicates (list)
119 (do ((next list
(rest next
)))
120 ((not (consp next
)) nil
)
121 (if (member (first next
) (rest next
)) (return t
))))
123 ;;; version of assoc using eq -- should be faster than regular assoc
124 (defun assoc-eq (item alist
)
125 (declare (inline car eq
))
127 (if (eq (car i
) item
) (return i
))))
129 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
131 ;;;; Predicate and Checking Functions
133 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
135 (defun check-non-nil-symbol (x)
136 (unless (and x
(symbolp x
)) (error "bad symbol - ~s" x
)))
138 (defun check-object (x)
139 (if (objectp x
) x
(error "bad object - ~s" x
)))
141 (defun kind-of-p (x y
)
143 Returns T is X and Y are objects and X inherits from Y, NIL otherwise."
144 (if (and (objectp x
) (objectp y
))
145 (if (member y
(ls-object-preclist x
)) t nil
)
148 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
150 ;;;; Precedence List Functions
152 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
154 ;;;; find set of object and ancestors
155 (defun find-SC (object)
156 (copy-list (ls-object-preclist (check-object object
))))
158 ;;;; find set of object and ancestors
159 (defun find-S (object)
161 (parents (ls-object-parents object
) (cdr parents
)))
162 ((not (consp parents
))
163 (delete-duplicates (cons object result
)))
164 (setf result
(nconc (find-SC (first parents
)) result
))))
166 ;;;; find local precedence ordering
167 (defun find-RC (object)
168 (let ((list (copy-list (ls-object-parents (check-object object
)))))
169 (do ((next list
(rest next
)))
170 ((not (consp next
)) list
)
171 (setf (first next
) (cons object
(first next
)))
172 (setf object
(rest (first next
))))))
174 ;;;; find partial precedence ordering
179 (delete-duplicates result
))
180 (setf result
(nconc result
(find-RC (first S
))))))
182 ;;;; check if x has a predecessor according to R
183 (defun has-predecessor (x R
)
185 (if (and (consp cell
) (eq x
(rest cell
))) (return t
))))
187 ;;;; find list of objects in S without predecessors, by R
188 (defun find-no-predecessor-list (S R
)
191 (unless (has-predecessor x R
) (setf result
(cons x result
))))))
193 ;;;; find the position of child, if any, of x in P, the list found so far
194 (defun child-position (x P
)
196 (declare (fixnum count
))
198 (if (member x
(ls-object-parents next
)) (return count
))
201 ;;;; find the next object in the precedence list from objects with no
202 ;;;; predecessor and current list.
203 (defun next-object (no-preds P
)
205 ((not (consp no-preds
)) nil
)
206 ((not (consp (rest no-preds
))) (first no-preds
))
210 (declare (fixnum count
))
211 (dolist (x no-preds result
)
212 (let ((tcount (child-position x P
)))
213 (declare (fixnum tcount
))
214 (when (> tcount count
)
216 (setf count tcount
))))))))
218 ;;;; remove object x from S
219 (defun trim-S (x S
) (delete x S
))
221 ;;;; remove all pairs containing x from R. x is assumed to have no
222 ;;;; predecessors, so only the first position is checked.
223 (defun trim-R (x R
) (delete x R
:key
#'first
))
225 ;;;; calculat the object's precedence list
226 (defun precedence-list (object)
227 (do* ((S (find-S object
))
233 (setf no-preds
(find-no-predecessor-list S R
))
234 (setf next
(next-object no-preds P
))
235 (if (null next
) (error "inconsistent precedence order"))
236 (setf P
(nconc P
(list next
)))
237 (setf S
(trim-S next S
))
238 (setf R
(trim-R next R
))))
240 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
242 ;;;; Object Construction Functions
244 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
246 (defun calculate-preclist (object)
247 (let ((parents (ls-object-parents (check-object object
))))
248 (if (not (consp parents
)) (error "bad parent list - ~s" parents
))
249 (if (consp (rest parents
))
250 (precedence-list object
)
251 (let ((parent (check-object (first parents
))))
252 (cons object
(ls-object-preclist parent
))))))
254 (defun check-parents (parents)
256 ((or (null parents
) (objectp parents
)) parents
)
258 (dolist (x parents
) (check-object x
))
259 (if (has-duplicates parents
) (error "parents may not contain duplicates")))
260 (t (error "bad parents - ~s" parents
))))
262 (defun make-basic-object (parents object
)
263 (check-parents parents
)
265 (if (not (objectp object
)) (setf object
(make-object-structure)))
267 (setf (ls-object-preclist object
) (ls-object-preclist *object
*))
268 (setf (ls-object-parents object
)
269 (cond ((null parents
) (list *object
*))
270 ((objectp parents
) (list parents
))
272 (setf (ls-object-preclist object
) (calculate-preclist object
))
276 (defun make-object (&rest parents
)
277 "Args: (&rest parents)
278 Returns a new object with parents PARENTS. If PARENTS is NIL,
279 (list *OBJECT*) is used."
280 (make-basic-object parents NIL
))
282 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
284 ;;;; Constraint Hook Functions
286 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
288 (pushnew :constrainthooks
*features
*)
289 #+:constrainthooks
(defvar *message-hook
* nil
)
290 #+:constrainthooks
(defvar *set-slot-hook
* nil
)
293 (defun check-constraint-hooks (object sym slot
)
294 (let ((hook (if slot
*set-slot-hook
* *message-hook
*)))
297 (let ((*set-slot-hook
* nil
))
298 (funcall hook object sym
))
299 (let ((*message-hook
* nil
))
300 (funcall hook object sym
))))))
302 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
304 ;;;; Slot Access Functions
306 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
308 (defun make-slot-entry (x y
) (cons x y
))
309 (defun slot-entry-p (x) (consp x
))
310 (defun slot-entry-key (x) (first x
))
311 (defun slot-entry-value (x) (rest x
))
312 (defun set-slot-entry-value (x v
) (setf (rest x
) v
))
313 (defsetf slot-entry-value set-slot-entry-value
)
315 (defun find-own-slot (x slot
)
316 (if (objectp x
) (assoc-eq slot
(ls-object-slots x
))))
318 (defun find-slot (x slot
)
320 (let ((preclist (ls-object-preclist x
)))
321 (dolist (object preclist
)
322 (let ((slot-entry (find-own-slot object slot
)))
323 (if slot-entry
(return slot-entry
)))))))
325 (defun add-slot (x slot value
)
327 (check-non-nil-symbol slot
)
328 (let ((slot-entry (find-own-slot x slot
)))
330 (setf (slot-entry-value slot-entry
) value
)
331 (setf (ls-object-slots x
)
332 (cons (make-slot-entry slot value
) (ls-object-slots x
)))))
335 (defun delete-slot (x slot
)
337 (setf (ls-object-slots x
)
338 (delete slot
(ls-object-slots x
) :key
#'slot-entry-key
)))
340 (defun get-slot-value (x slot
&optional no-err
)
342 (let ((slot-entry (find-slot x slot
)))
343 (if (slot-entry-p slot-entry
)
344 (slot-entry-value slot-entry
)
345 (unless no-err
(error "no slot named ~s in this object" slot
)))))
347 (defun set-slot-value (x slot value
)
349 (let ((slot-entry (find-own-slot x slot
)))
351 ((slot-entry-p slot-entry
)
352 (set-slot-entry-value slot-entry value
)
353 #+:constrainthooks
(check-constraint-hooks x slot t
))
355 (if (find-slot x slot
)
356 (error "object does not own slot ~s" slot
)
357 (error "no slot named ~s in this object" slot
))))))
359 (defun slot-value (slot)
361 Must be used in a method. Returns the value of current objects slot
363 (get-slot-value (get-self) slot
))
365 (defun slot-value-setf (slot value
)
366 (set-slot-value (get-self) slot value
))
368 (defsetf slot-value slot-value-setf
)
370 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
372 ;;;; Method Access Functions;
374 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
376 (defun make-method-entry (x y
) (cons x y
))
377 (defun method-entry-p (x) (consp x
))
378 (defun method-entry-key (x) (first x
))
379 (defun method-entry-method (x) (rest x
))
380 (defun set-method-entry-method (x v
) (setf (rest x
) v
))
381 (defsetf method-entry-method set-method-entry-method
)
383 ;(defun find-own-method (x selector)
384 ; (if (objectp x) (assoc selector (ls-object-methods x))))
385 (defun find-own-method (x selector
)
386 (if (objectp x
) (assoc-eq selector
(ls-object-methods x
))))
388 (defun find-lsos-method (x selector
)
390 (let ((preclist (ls-object-preclist x
)))
391 (dolist (object preclist
)
392 (let ((method-entry (find-own-method object selector
)))
393 (if method-entry
(return method-entry
)))))))
395 (defun add-lsos-method (x selector value
)
397 (check-non-nil-symbol selector
)
398 (let ((method-entry (find-own-method x selector
)))
400 (setf (method-entry-method method-entry
) value
)
401 (setf (ls-object-methods x
)
402 (cons (make-method-entry selector value
) (ls-object-methods x
)))))
405 (defun delete-method (x selector
)
407 (setf (ls-object-methods x
)
408 (delete selector
(ls-object-methods x
) :key
#'method-entry-key
)))
410 (defun get-message-method (x selector
&optional no-err
)
412 (let ((method-entry (find-lsos-method x selector
)))
413 (if (method-entry-p method-entry
)
414 (method-entry-method method-entry
)
415 (unless no-err
(error "no method for selector ~s" selector
)))))
417 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
419 ;;;; Message Sending Functions
421 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
423 (defvar *current-preclist
* nil
)
424 (defvar *current-selector
* nil
)
426 (defun sendmsg (object selector preclist args
)
427 (let ((method-entry nil
)
430 ;; look for the message in the precedence list
432 (setf method-entry
(find-own-method (first preclist
) selector
))
433 (if (or method-entry
(not (consp preclist
))) (return))
434 (setf preclist
(rest preclist
)))
436 ((null method-entry
) (error "no method for selector ~s" selector
))
437 ((not (method-entry-p method-entry
)) (error "bad method entry"))
438 (t (setf method
(method-entry-method method-entry
))))
441 (let ((*current-preclist
* preclist
)
442 (*current-selector
* selector
)
444 (multiple-value-prog1
445 (apply method object args
)
446 #+:constrainthooks
(check-constraint-hooks object selector nil
)))))
448 ;;;; built-in send function
449 (defun send (object selector
&rest args
)
450 "Args: (object selector &rest args)
451 Applies first method for SELECTOR found in OBJECT's precedence list to
453 (sendmsg object selector
(ls-object-preclist object
) args
))
455 ;;;; call-next-method - call inherited version of current method
456 (defun call-next-method (&rest args
)
458 Funcalls next method for current selector and precedence list. Can only be
460 (sendmsg *self
* *current-selector
* (rest *current-preclist
*) args
))
462 ;;;; call-method - call method belonging to another object on current object
463 (defun call-method (object selector
&rest args
)
464 "Args (object selector &rest args)
465 Funcalls method for SELECTOR found in OBJECT to SELF. Can only be used in
467 (sendmsg *self
* selector
(ls-object-preclist object
) args
))
469 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
471 ;;;; Object Documentation Functions
473 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
475 (defun find-documentation (x sym add
)
477 (let ((doc (find-own-slot x
'documentation
)))
478 (if (and (null doc
) add
) (add-slot x
'documentation nil
))
479 (if (slot-entry-p doc
) (assoc sym
(slot-entry-value doc
))))))
481 (defun add-documentation (x sym value
)
483 (check-non-nil-symbol sym
)
484 (let ((doc-entry (find-documentation x sym t
)))
486 ((not (null doc-entry
))
487 (setf (rest doc-entry
) value
))
491 (cons (cons sym value
)
492 (get-slot-value x
'documentation
))))))
495 (defun get-documentation (x sym
)
497 (dolist (object (ls-object-preclist x
))
498 (let ((doc-entry (find-documentation x sym nil
)))
499 (if doc-entry
(return (rest doc-entry
))))))
501 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
505 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
507 (defmacro defmeth
(object name arglist first
&rest body
)
508 "Syntax: (defmeth object name lambda-list [doc] {form}*)
509 OBJECT must evaluate to an existing object. Installs a method for NAME in
510 the value of OBJECT and installs DOC in OBJECTS's documentation."
511 (if (and body
(stringp first
))
513 (add-lsos-method ,object
,name
514 #'(lambda (self ,@arglist
) (block ,name
,@body
)))
515 (add-documentation ,object
,name
,first
)
518 (add-lsos-method ,object
,name
519 #'(lambda (self ,@arglist
) (block ,name
,first
,@body
)))
522 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
524 ;;;; Prototype Construction Functions and Macros
526 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
528 (defun find-instance-slots (x slots
)
529 (let ((result (nreverse (delete-duplicates (copy-list slots
)))))
530 (dolist (parent (ls-object-parents x
) (nreverse result
))
531 (dolist (slot (get-slot-value parent
'instance-slots
))
532 (pushnew slot result
)))))
534 (defun get-initial-slot-value (object slot
)
535 (let ((entry (find-slot object slot
)))
536 (if (slot-entry-p entry
) (slot-entry-value entry
))))
538 (defun make-prototype (object name ivars cvars doc set
)
539 (setf ivars
(find-instance-slots object ivars
))
540 (add-slot object
'instance-slots ivars
)
541 (add-slot object
'proto-name name
)
544 (add-slot object slot
(get-initial-slot-value object slot
)))
547 (add-slot object slot nil
))
549 (if (and doc
(stringp doc
))
550 (add-documentation object
'proto doc
))
552 (if set
(set name object
)))
554 (defmacro defproto
(name &optional ivars cvars parents doc
)
555 "Syntax (defproto name &optional ivars cvars (parent *object*) doc)
556 Makes a new object prototype with instance variables IVARS, 'class'
557 variables CVARS and parents PARENT. PARENT can be a single object or
558 a list of objects. IVARS and CVARS must be lists."
559 (let ((obsym (gensym))
563 (let* ((,namesym
',name
)
565 (,obsym
(make-basic-object (if (listp ,parsym
)
569 (make-prototype ,obsym
,namesym
,ivars
,cvars
,doc t
)
572 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
574 ;;;; Initialize the Root Object
576 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
578 (setf (ls-object-preclist *object
*) (list *object
*))
579 (add-slot *object
* 'instance-slots nil
)
580 (add-slot *object
* 'proto-name
'*object
*)
582 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
584 ;;;; *OBJECT* Methods
586 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
588 (defmeth *object
* :isnew
(&rest args
)
589 "Method args: (&rest args)
590 Checks ARGS for keyword arguments matching slots and uses them to
593 (dolist (slot-entry (ls-object-slots self
))
594 (let* ((slot (slot-entry-key slot-entry
))
595 (key (intern (symbol-name slot
) (find-package 'keyword
)))
596 (val (slot-value slot
))
597 (new-val (getf args key val
)))
598 (unless (eq val new-val
) (setf (slot-value slot
) new-val
)))))
601 (defmeth *object
* :has-slot
(slot &key own
)
602 "Method args: (slot &optional own)
603 Returns T if slot SLOT exists, NIL if not. If OWN is not NIL
604 only checks the object; otherwise check the entire precedence list."
605 (let ((entry (if own
(find-own-slot self slot
) (find-slot self slot
))))
608 (defmeth *object
* :add-slot
(slot &optional value
)
609 "Method args: (slot &optional value)
610 Installs slot SLOT in object, if it does not already exist, and
611 sets its value to VLAUE."
612 (add-slot self slot value
)
615 (defmeth *object
* :delete-slot
(slot)
617 Deletes slot SLOT from object if it exists."
618 (delete-slot self slot
)
621 (defmeth *object
* :own-slots
()
623 Returns list of names of slots owned by object."
624 (mapcar #'slot-entry-key
(ls-object-slots self
)))
626 (defmeth *object
* :has-method
(selector &key own
)
627 "Method args: (selector &optional own)
628 Returns T if method for SELECTOR exists, NIL if not. If OWN is not NIL
629 only checks the object; otherwise check the entire precedence list."
631 (find-own-method self selector
)
632 (find-lsos-method self selector
))))
635 (defmeth *object
* :add-method
(selector method
)
636 "Method args: (selector method)
637 Installs METHOD for SELECTOR in object."
638 (add-lsos-method self selector method
)
641 (defmeth *object
* :delete-method
(selector)
642 "Method args: (selector)
643 Deletes method for SELECTOR in object if it exists."
644 (delete-method self selector
)
647 (defmeth *object
* :get-method
(selector)
648 "Method args: (selector)
649 Returns method for SELECTOR symbol from object's precedence list."
650 (get-message-method self selector
))
652 (defmeth *object
* :own-methods
()
654 Returns copy of selectors for methods owned by object."
655 (mapcar #'method-entry-key
(ls-object-methods self
)))
657 (defmeth *object
* :parents
()
659 Returns copy of parents list."
660 (copy-list (ls-object-parents self
)))
662 (defmeth *object
* :precedence-list
()
664 Returns copy of the precedence list."
665 (copy-list (ls-object-preclist self
)))
667 (defmeth *object
* :show
(&optional
(stream t
))
669 Prints object's internal data."
670 (format stream
"Slots = ~s~%" (ls-object-slots self
))
671 (format stream
"Methods = ~s~%" (ls-object-methods self
))
672 (format stream
"Parents = ~s~%" (ls-object-parents self
))
673 (format stream
"Precedence List = ~s~%" (ls-object-preclist self
))
676 (defmeth *object
* :reparent
(&rest parents
)
677 "Method args: (&rest parents)
678 Changes precedence list to correspond to PARENTS. Does not change descendants."
679 (make-basic-object parents self
))
681 (defmeth *object
* :make-prototype
(name &optional ivars
)
682 (make-prototype self name ivars nil nil nil
)
685 (defmeth *object
* :internal-doc
(sym &optional new
)
686 "Method args (topic &optional value)
687 Retrieves or installs documentation for topic."
688 (if new
(add-documentation self sym new
))
689 (get-documentation self sym
))
691 (defmeth *object
* :new
(&rest args
)
692 "Method args: (&rest args)
693 Creates new object using self as prototype."
694 (let* ((object (make-object self
)))
695 (if (slot-value 'instance-slots
)
696 (dolist (s (slot-value 'instance-slots
))
697 (send object
:add-slot s
(slot-value s
))))
698 (apply #'send object
:isnew args
)
701 (defmeth *object
* :retype
(proto &rest args
)
702 "Method args: (proto &rest args)
703 Changes object to inherit directly from prototype PROTO. PROTO
704 must be a prototype and SELF must not be one."
705 (if (send self
:has-slot
'instance-slots
:own t
)
706 (error "can't retype a prototype"))
707 (if (not (send proto
:has-slot
'instance-slots
:own t
))
708 (error "not a prototype - ~a" proto
))
709 (send self
:reparent proto
)
710 (dolist (s (send proto
:slot-value
'instance-slots
))
711 (send self
:add-slot s
(slot-value s
)))
712 (apply #'send self
:isnew args
)
715 (defmeth *object
* :print
(&optional
(stream *standard-output
*))
716 "Method args: (&optional (stream *standard-output*))
717 Default object printing method."
719 ((send self
:has-slot
'proto-name
)
721 "#<Object: ~D, prototype = ~A>"
722 (ls-object-serial self
)
723 (slot-value 'proto-name
)))
724 (t (format stream
"#<Object: ~D>" (ls-object-serial self
)))))
726 (defmeth *object
* :slot-value
(sym &optional
(val nil set
))
727 "Method args: (sym &optional val)
728 Sets and retrieves value of slot named SYM. Sugnals an error if slot
730 (if set
(setf (slot-value sym
) val
))
733 (defmeth *object
* :slot-names
()
735 Returns list of slots available to the object."
737 (mapcar #'(lambda (x) (send x
:own-slots
))
738 (send self
:precedence-list
))))
740 (defmeth *object
* :method-selectors
()
742 Returns list of method selectors available to object."
744 (mapcar #'(lambda (x) (send x
:own-methods
))
745 (send self
:precedence-list
))))
748 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
750 ;;;; Object Help Methods
752 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
754 (defmeth *object
* :doc-topics
()
756 Returns all topics with documentation for this object."
762 (if (send x
:has-slot
'documentation
:own t
)
763 (send x
:slot-value
(quote documentation
))))
764 (send self
:precedence-list
))))))
766 (defmeth *object
* :documentation
(topic &optional
(val nil set
))
767 "Method args: (topic &optional val)
768 Retrieves or sets object documentation for topic."
769 (if set
(send self
:internal-doc topic val
))
770 (let ((val (dolist (i (send self
:precedence-list
))
771 (let ((val (send i
:internal-doc topic
)))
772 (if val
(return val
))))))
775 (defmeth *object
* :delete-documentation
(topic)
776 "Method args: (topic)
777 Deletes object documentation for TOPIC."
778 (setf (slot-value 'documentation
)
779 (remove :title nil
:test
#'(lambda (x y
) (eql x
(first y
)))))
782 (defmeth *object
* :help
(&optional topic
)
783 "Method args: (&optional topic)
784 Prints help message for TOPIC, or genreal help if TOPIC is NIL."
786 (let ((doc (send self
:documentation topic
)))
788 (doc (princ topic
) (terpri) (princ doc
) (terpri))
789 (t (format t
"Sorry, no help available on ~a~%" topic
))))
790 (let ((topics (stable-sort (copy-seq (send self
:doc-topics
))
792 (string-lessp (string x
) (string y
)))))
793 (proto-doc (send self
:documentation
'proto
)))
794 (if (send self
:has-slot
'proto-name
)
795 (format t
"~s~%" (slot-value 'proto-name
)))
796 (when proto-doc
(princ proto-doc
) (terpri))
797 (format t
"Help is available on the following:~%~%")
798 (dolist (i topics
) (format t
"~s " i
))
802 (defmeth *object
* :compile-method
(name)
804 Compiles method NAME unless it is already compiled. The object must
806 (unless (send self
:has-method name
)
807 (error "No ~s method in this object" name
))
808 (unless (send self
:has-method name
:own t
)
809 (error "Object does not own ~s method" name
))
810 (let ((fun (send self
:get-method name
)))
811 (unless (compiled-function-p fun
)
812 (multiple-value-bind (form env
) (function-lambda-expression fun
)
815 "method may have been defined in non-null environment"))
816 (send self
:add-method name
(compile nil form
))))))