[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[barmar@Think.COM: MULTIPLE-VALUE-SETQ and SYMBOL-MACROLET interaction]
- To: CommonLoops.pa@Xerox.COM
- Subject: [barmar@Think.COM: MULTIPLE-VALUE-SETQ and SYMBOL-MACROLET interaction]
- From: Gregor.pa@Xerox.COM
- Date: Fri, 29 Jul 88 11:10 PDT
- Fcc: BD:>Gregor>mail>outgoing-mail-3.text.newest
- Included-msgs: <19880729021542.8.BARMAR@OCCAM.THINK.COM>, The message of 28 Jul 88 19:15 PDT from barmar@Think.COM, The message of 28 Jul 88 19:15 PDT from Barry Margolin
- Line-fold: no
This message from Barmar points out an ommission in the spec, and a bug
in the current version of PCL. This is fixed in the next version of
PCL, and a patch is included at the end of this message.
Date: Thu, 28 Jul 88 19:15 PDT
From: Barry Margolin <barmar@Think.COM>
In CLOS, the way to access slots as if they were lexical variables is to
use WITH-SLOTS, which uses SYMBOL-MACROLET to macroexpand occurrences of
the slot names into (SLOT-VALUE <object> '<name>) forms. It also
converts any SETQ special forms into SETF forms.
But what about MULTIPLE-VALUE-SETQ? If SETQ is allowed to assign slot
variables then so should MULTIPLE-VALUE-SETQ.
To install this patch and save time:
1) edit boot.lisp
2) compile boot.lisp in an already loaded pcl
3) put this changes in their own file, with (in-package 'pcl)
4) compile and load that file in your running pcl
You do not need to recompile or reload your application.
;from boot.lisp
(defmacro with-slots
(slots instance &body body &environment env)
(let ((gensym (gensym)))
(expand-with-slots (mapcar #'(lambda (ss)
(if (symbolp ss) (list ss ss) ss))
slots)
body
env
gensym
instance
#'(lambda (s) `(slot-value ,gensym ',s)))))
(defmacro with-accessors
(slot-accessor-pairs instance &body body &environment env)
(let ((gensym (gensym)))
(expand-with-slots slot-accessor-pairs
body
env
gensym
instance
#'(lambda (a) `(,a ,gensym)))))
(defun expand-with-slots (specs body env gensym instance translate-fn)
`(let ((,gensym ,instance))
,@(and (symbolp instance)
`((declare (variable-rebinding ,gensym ,instance))))
,gensym
,@(walk-form body
env
#'(lambda (f c e)
(declare (ignore e))
(expand-with-slots-internal specs
f
c
translate-fn)))))
(defun expand-with-slots-internal (specs form context translate-fn &aux entry)
(cond ((not (eq context :eval)) form)
((symbolp form)
(if (setq entry (assoc form specs))
(funcall translate-fn (cadr entry))
form))
((not (listp form)) form)
((member (car form) '(setq setf))
;; Have to be careful. We must only convert the form to a SETF
;; form when we convert one of the 'logical' variables to a form
;; Otherwise we will get looping in implementations where setf
;; is a macro which expands into setq.
(let ((kind (car form)))
(labels ((scan-setf (tail)
(if (null tail)
nil
(walker::relist*
tail
(if (setq entry (assoc (car tail) specs))
(progn (setq kind 'setf)
(funcall translate-fn (cadr entry)))
(car tail))
(cadr tail)
(scan-setf (cddr tail))))))
(let (new-tail)
(setq new-tail (scan-setf (cdr form)))
(walker::recons form kind new-tail)))))
((eq (car form) 'multiple-value-setq)
(let* ((vars (cadr form))
(gensyms (mapcar #'(lambda (i) (declare (ignore i)) (gensym))
vars)))
`(multiple-value-call #'(lambda ,gensyms
.,(mapcar #'(lambda (v g) `(setf ,v ,g))
vars
gensyms))
,(caddr form))))
(t form)))
-------