Re: [PATCH] Fix broken defsetf for places with keywords.

Kaz Kylheku <[email protected]> Fri, 28 Jun 2019 15:42:46 -0700
Newsgroups gmane.lisp.clisp.general
Message-ID <[email protected]>
On 2019-06-28 07:57, Sam Steingold wrote:
> Hi Kaz,
> 
> Sorry about not replying earlier - I thought that you were actually
> planning to work more on your patch.
> 
>> * Kaz Kylheku <[email protected]> [2019-03-01 16:45:18 -0800]:
>> 
>> Note the code is not prepared to deal with situations when the
>> keywords are given by evaluated expressions. I am not fixing that
>> aspect of it, and it's probably a bad idea; a virtue of the defsetf
>> logic over keyword arguments is that it understands keyword
>> arguments.
> 
> How do other implementations handle this?

Who cares. :)

> It is unclear if this aspect _can_ be easily fixed.
> Both CLISP and SBCL fail identically:
> 
> 
> ```
> (defparameter *xy* (make-array '(10 10) :initial-element NIL))
> (defun xy-s (&key ((x x) 0) ((y y) 0)) (aref *xy* x y))
> (defun xy-k (&key (x 0) (y 0)) (aref *xy* x y))
> (defun set-xy-s (new-value &key ((x x) 0) ((y y) 0))
>   (setf (aref *xy* x y) new-value))
> (defun set-xy-k (new-value &key (x 0) (y 0))
>   (setf (aref *xy* x y) new-value))
> (defsetf xy-s (&key ((x x) 0) ((y y) 0)) (store)
>   `(set-xy-s ,store 'x ,x 'y ,y))
> (defsetf xy-k (&key (x 0) (y 0)) (store)
>   `(set-xy-k ,store :x ,x :y ,y))
> 
> (assert (eql NIL (xy-k :x 1)))
> (assert (eql NIL (xy-s 'x 1)))
> (assert (eql 10 (setf (xy-k :x 1) 10)))
> (assert (eql 20 (setf (xy-s 'x 2) 20)))

Unmodified CLISP fails on the above line:

    The argument 'X to XY-S should be a keyword

Patched works. That is representative of what I'm trying to fix.

> (assert (eql 20 (xy-k :x 20)))
> (assert (eql 10 (xy-s 'x 10)))

The immediately preceding two expressions attempt an OOB array access;
I commented them out.

> (let ((a 'x) (b 'y))
>   (setf (xy-s a 1 b 2) 3)
>   (setf (xy-s b 5 a 9) 14))

Patched CLISP still fails on the *let*, as I expect. That is not 
supported,
and cannot easily be.

Note that even if it were supported, it wouldn't work for your test 
cases
here because ... your store form hard codes the symbols:

   (set-xy-s ,store 'x ,x 'y ,y)

I don't see a way of fixing this; how will the scope of your store form
receive the value?  In other words:

   (set-xy-s ,store ,what-goes-here ,x ,and-here ,y)  ?

those symbols have to come from the defsetf syntax somewhere.

If someone wants this kind of run-time behavior
with keywords, what they can do is imply register the function
with the short form of defset:

   [1]> (defsetf foo set-foo)
   FOO
   [2]> (macroexpand '(setf (foo :x 1 :y 1) 42))
   (SET-FOO :X 1 :Y 1 42) ;

Right? This approach will blindly take any arguments and gensymize
everything:

   [3]> (macroexpand '(incf (foo (h) (i) (j) (k))))
   (LET*
    ((#:TEMP-3362 (H)) (#:TEMP-3361 (I)) (#:TEMP-3360 (J)) (#:TEMP-3359 
(K))
     (#:NEW-3358 (+ (FOO #:TEMP-3362 #:TEMP-3361 #:TEMP-3360 #:TEMP-3359) 
1)))
    (SET-FOO #:TEMP-3362 #:TEMP-3361 #:TEMP-3360 #:TEMP-3359 #:NEW-3358)) 
;

the setter is agnostic about keywords; only the function knows
about them and that's where any error checking takes place.

I think that the support for keyword arguments in DEFSETF
is specifically to give the programmer an alternative from the above
loose treatment.

Anyway, the static treatment of the indicator symbols is, IIRC, deeply
designed into the strategy used by CLISP's expander. Making it somehow
work more flexibly is out of scope of my bugfix.

> (assert (eql 3 (xy-s 'y 2 'x 1)))
> (assert (eql 3 (xy-k :y 2 :x 1)))
> (assert (eql 14 (xy-k :x 9 :y 5)))
> (assert (eql 14 (xy-s 'x 9 'y 5)))

I've moved these into the LET; they die with it.

> (setf (xy-k (if t :x :y) 44 (if nil :x :y) 22))

You have a missing new value here; I made it ..y) 22) 42).

No, computed keywords don't work also for the same reason;
SETF won't evaluate those arguments. The diagnostic isn't great:

   "illegal keyword/value pair #:G2971, #:G2972 in argument list
    The allowed keywords are (:X :Y)."

But the second sentence of tells the truth, at least.

Cheers ...



_______________________________________________
clisp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/clisp-list