Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!uakari.primate.wisc.edu!caen!spool.mu.edu!agate!stanford.edu!lucid.com!karoshi!fy From: fy@lucid.com (Frank Yellin) Newsgroups: comp.lang.lisp Subject: Re: (setf (values ... Message-ID: Date: 14 Jun 91 15:09:02 GMT References: <1991Jun13.204847.5625@jpl-devvax.jpl.nasa.gov> <1991Jun13.170657.23523@hellgate.utah.edu> Sender: usenet@lucid.com Organization: Lucid, Inc., Menlo Park, CA Lines: 84 In-Reply-To: moore%defmacro.utah.edu@cs.utah.edu's message of 13 Jun 91 23:06:57 GMT Tim Moore gives the following setf method for values: > (define-setf-method values (&rest args &environment env) > (let ((vars nil) > (vals nil) > (store-vars nil) > (store-forms nil) > (access-forms nil) > (nil-store-vars nil)) > (dolist (arg args) > (multiple-value-bind (these-vars these-vals these-store-vars > store-form access-form) > (get-setf-method-multiple-value arg env) > (setq vars (nconc vars these-vars)) > (setq vals (nconc vals these-vals)) > (push (car these-store-vars) store-vars) > (setq nil-store-vars (nconc nil-store-vars (cdr these-store-vars))) > (push store-form store-forms) > (push access-form access-forms))) > (values (nconc vars nil-store-vars) > (nconc vals (make-list (length nil-store-vars))) > (nreverse store-vars) > `(values ,.(nreverse store-forms)) > `(values ,.(nreverse access-forms))))) I have three very minor nits. And they really are minor. I'd be very hard pressed to write real code for which the above didn't work. Nit #1) The above code lets each of the 's in (values .. ) itself have a multiple-value setf-method. Does this really make sense? Does (setf (values a b (values c d) e) ...) really mean that I want "d" set to nil? I suppose I'm trying to open up the philosophical question of whether there are places that I really want get-setf-method instead of get-setf-method-multiple-value. Does (push x (values a b)) make any sense? What about (rotatef (values (values a b)) (values (values c d)))? Very minor Nit #2) Temporarily put aside Nit #1. Using the above code > (get-setf-method-multiple-value '(values a (values b c))) (#:G3) (NIL) (#:G1 #:G2) (VALUES (SETQ A #:G1) (VALUES (SETQ B #:G2) (SETQ C #:G3))) (VALUES A (VALUES B C)) I don't think that the binding of #:G3 to nil should be done as part of the dummies to values binding. The binding of newvals to the new values should only be done as part of the setter. I would have been happier with > (get-setf-method-multiple-value '(values a (values b c))) () () (#:G1 #:G2) (VALUES (SETQ A #:G1) (LET ((#:G3 NIL)) (VALUES (SETQ B #:G2) (SETQ C #:G3)))) (VALUES A (VALUES B C)) Nit #3) The specifications in CLtL2 allow the "newvar" list to be empty! Sort of silly, but perfectly legal. The above code implicitly believes that each newvars list (what is called these-store-vars in the code) contains at least var. Imagine one writing the lisp equivalent of /dev/null: (defun hole () (values)) (def-setf-method hole () () (values)) I would expect something like > (get-setf-method-multiple-value (values (hole) a)) () () (#:G1 #:G2) (LOCALLY (DECLARE (IGNORE #:G1)) (VALUES (VALUES) (SETQ A #:G2))) (VALUES (HOLE) A) Where the #:G1 and the (LOCALLY (DECLARE (IGNORE #:G1)) ... ) are created by the setf method for values. -- Frank Yellin fy@lucid.com