Hello,
I am wondering if anyone can explain the reason for the defined but not used variable in setf that this code is experiencing:
CL-USER> (set-macro-character #$ (lambda (stream char) (declare (ignore char)) (let ((v (read stream))) (list (get v 'setf-handler-name) v))))
(defmacro defactive (var value &key write-handler read-handler) (let ((setf-handler-name (gensym))) `(progn (defparameter ,var ,value) (defmacro ,setf-handler-name (,var) (let ((read-handler (gensym))) `(let ((,read-handler (get ',',var :read-handler))) (if ,read-handler (funcall ,read-handler (eval ,',var)) ,',var)))) (defsetf ,setf-handler-name (,var) (new-val) (let ((write-handler (gensym))) `(let ((,write-handler (get ',',var :write-handler))) (when ,write-handler (funcall ,write-handler (eval ,',var) ,new-val)) (setf ,',var ,new-val)))) (setf (get ',var 'setf-handler-name) ',setf-handler-name) (setf (get ',var :write-handler) ,write-handler) (setf (get ',var :read-handler) ,read-handler) ,value)))
(defmacro setactive (var &key read-handler write-handler) `(progn (when ,read-handler (setf (get ',var :read-handler) ,read-handler)) (when ,write-handler (setf (get ',var :write-handler) ,write-handler))))
(defactive x 0 :write-handler (lambda (old-val new-val) (format t "old: ~A new: ~A" old-val new-val)) :read-handler (lambda (val) (format t "value: ~A" val) val)) ;(setactive x :read-handler (lambda (val) (format t "~A !!! ~A" val))) ;(setactive x :write-handler (lambda (old-val new-val) (format t "~A !!! ~A" old-val new-val)))
(defactive d6 (random 6) :read-handler (lambda (val) (let ((old val)) (setf d6 (random 6)) old)))
STYLE-WARNING: redefining COMMON-LISP-USER::DEFACTIVE in DEFMACRO STYLE-WARNING: redefining COMMON-LISP-USER::SETACTIVE in DEFMACRO 1 CL-USER> (setf $x 10) ; in: SETF (#:G1129 X) ; (LET* ((#:G1175 X)) ; (MULTIPLE-VALUE-BIND (#:G1176) ; 10 ; (LET ((#:G1177 #)) ; (WHEN #:G1177 (FUNCALL #:G1177 # #:G1176)) ; (SETF X #:G1176)))) ; ; caught STYLE-WARNING: ; The variable #:G1175 is defined but never used. ; ; compilation unit finished ; caught 1 STYLE-WARNING condition old: 0 new: 10 10
-- Burton Samograd http://kruhft.dyndns.org
- Burton Samograd ohegba.fnzbtenq@tznvy.pbz [2012-01-23 06:18:16 -0700]:
; caught STYLE-WARNING: ; The variable #:G1175 is defined but never used.
I think this is a compiler bug: "defined but never used" warnings should only be signaled for interned symbols, not gensyms. Macros often define gensyms which might not be used by some macro uses.
On Mon, Jan 23, 2012 at 5:18 AM, Burton Samograd burton.samograd@gmail.com wrote:
Hello,
I am wondering if anyone can explain the reason for the defined but not used variable in setf that this code is experiencing:
I don't know for sure, but there are a couple of things that are odd about your macro-writing macro. One is that in the `defmacro' and `defsetf' it generates, the `var' passed in the outer macro call is reused as a parameter of the generated macro and setf expander. The other is the two calls to `eval'.
I haven't taken the time to work out why those things are there, but I would suggest they probably shouldn't be. Try getting rid of them and see what happens.
-- Scott
(defmacro defactive (var value &key write-handler read-handler) (let ((setf-handler-name (gensym))) `(progn (defparameter ,var ,value) (defmacro ,setf-handler-name (,var) (let ((read-handler (gensym))) `(let ((,read-handler (get ',',var :read-handler))) (if ,read-handler (funcall ,read-handler (eval ,',var)) ,',var)))) (defsetf ,setf-handler-name (,var) (new-val) (let ((write-handler (gensym))) `(let ((,write-handler (get ',',var :write-handler))) (when ,write-handler (funcall ,write-handler (eval ,',var) ,new-val)) (setf ,',var ,new-val)))) (setf (get ',var 'setf-handler-name) ',setf-handler-name) (setf (get ',var :write-handler) ,write-handler) (setf (get ',var :read-handler) ,read-handler) ,value)))
Burton Samograd burton.samograd@gmail.com writes:
CL-USER> (setf $x 10) ; in: SETF (#:G1129 X) ; (LET* ((#:G1175 X)) ; (MULTIPLE-VALUE-BIND (#:G1176) ; 10 ; (LET ((#:G1177 #)) ; (WHEN #:G1177 (FUNCALL #:G1177 # #:G1176)) ; (SETF X #:G1176)))) ; ; caught STYLE-WARNING: ; The variable #:G1175 is defined but never used.
I don't think it's a compiler error (there's no reason to treat uninterned symbols differently from interned ones).
Clearly, there's a single occurence of #:G1175, in the binding of the LET* form, and no use of it. You should either avoid generating it, or add a
(declare (ignorable #:G1175))
expression before the body of the LET*.
On Tue, 24 Jan 2012 07:04:43 +0100, Pascal J Bourguignon said:
Burton Samograd burton.samograd@gmail.com writes:
CL-USER> (setf $x 10) ; in: SETF (#:G1129 X) ; (LET* ((#:G1175 X)) ; (MULTIPLE-VALUE-BIND (#:G1176) ; 10 ; (LET ((#:G1177 #)) ; (WHEN #:G1177 (FUNCALL #:G1177 # #:G1176)) ; (SETF X #:G1176)))) ; ; caught STYLE-WARNING: ; The variable #:G1175 is defined but never used.
I don't think it's a compiler error (there's no reason to treat uninterned symbols differently from interned ones).
Clearly, there's a single occurence of #:G1175, in the binding of the LET* form, and no use of it. You should either avoid generating it, or add a
(declare (ignorable #:G1175))
expression before the body of the LET*.
Unfortunately neither of those solutions are possible directly, because the binding is generated by the SETF macro.
The binding is there because the reader macro expansion passes X as an argument, as in (#:G1129 X). The setf expander is defined using DEFSETF, so it has to evaluate all of its arguments in left-to-right order by binding them to temporary variables.
It isn't clear to me why this argument is needed, because the DEFSETF form can access the variable directly.
OTOH, the uses of EVAL look strange and I suspect the whole thing could be written more clearly without needing a separate DEFMACRO and DEFSETF for each DEFACTIVE form. That approach would need to use DEFINE-SETF-EXPANDER instead of DEFSETF.
On Tue, Jan 24, 2012 at 11:51 AM, Martin Simmons martin@lispworks.com wrote:
The binding is there because the reader macro expansion passes X as an argument, as in (#:G1129 X). The setf expander is defined using DEFSETF, so it has to evaluate all of its arguments in left-to-right order by binding them to temporary variables.
It isn't clear to me why this argument is needed, because the DEFSETF form can access the variable directly.
OTOH, the uses of EVAL look strange and I suspect the whole thing could be written more clearly without needing a separate DEFMACRO and DEFSETF for each DEFACTIVE form. That approach would need to use DEFINE-SETF-EXPANDER instead of DEFSETF.
Thank you all for your input on this problem. I have reworked the code to remove the eval's (for some reason I thought they were needed). I also removed the parameter to the setf-handler, I guess I thought that you needed a parameter to the setf handler and didn't realize that the variable binding was already there. This was really just a thought experiment in macro programming to implement a feature of ksh, and as always, I am just learning. Here is the reworked code:
(set-macro-character #$ (lambda (stream char) (declare (ignore char)) (let ((v (read stream))) (list (get v 'setf-handler-name)))))
(defmacro defactive (var value &key write-handler read-handler) (let ((setf-handler-name (gensym))) `(progn (defparameter ,var ,value) (defmacro ,setf-handler-name () (let ((read-handler (gensym))) `(let ((,read-handler (get ',',var :read-handler))) (if ,read-handler (funcall ,read-handler ,',var) ,',var)))) (defsetf ,setf-handler-name () (new-val) (let ((write-handler (gensym))) `(let ((,write-handler (get ',',var :write-handler))) (when ,write-handler (funcall ,write-handler ,',var ,new-val)) (setf ,',var ,new-val)))) (setf (get ',var 'setf-handler-name) ',setf-handler-name) (setf (get ',var :write-handler) ,write-handler) (setf (get ',var :read-handler) ,read-handler) ,value)))
(defmacro setactive (var &key read-handler write-handler) `(progn (when ,read-handler (setf (get ',var :read-handler) ,read-handler)) (when ,write-handler (setf (get ',var :write-handler) ,write-handler))))
(defactive x 0 :write-handler (lambda (old-val new-val) (format t "old: ~A new: ~A" old-val new-val)) :read-handler (lambda (val) (format t "value: ~A" val) val)) ;(setactive x :read-handler (lambda (val) (format t "~A !!! ~A" val))) ;(setactive x :write-handler (lambda (old-val new-val) (format t "~A !!! ~A" old-val new-val)))
(defactive d6 (1+ (random 6)) :read-handler (lambda (val) (let ((old val)) (setf d6 (1+ (random 6))) old)))
I will look into understanding define-setf-expander to see how this could be improved. I'm just happy that it works and I could implement it at all...long live user programmable languages!
-- Burton Samograd http://kruhft.dyndns.org