From: Robert Uhl
Subject: Canonical Way to Mask SETF?
Date: 
Message-ID: <m3vf3w3hum.fsf@4dv.net>
I'm playing with a menu system, and would like to be able to write the
following:

  (menu-item menu) -> item
  (setf (menu-item menu) item)

I figured that something like this would do the trick:

  (defun menu-item (menu)
         (getf menu :title))

  (defsetf menu-title (menu) (title)
  `(setf (getf ,menu :title) ,title))

But of course it doesn't work.  Any advice on how this needs to be
written?

Unfortunately there aren't too many online references which deal with
DEFSETF--at least none that I've found.

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
It is not necessary to enquire whether a woman would like something
for dessert.  The answer is yes, she would like something for dessert,
but she would like you to order it so she can pick at it with your
fork.  She does not want you to call attention to this by saying, `If
you wanted a dessert, why didn't you order one?'  You must understand,
she has the dessert she wants.  The dessert she wants is contained
within yours.
       --Merrill Marcoe, `An Insider's Guide to the American Woman'

From: Eric Lavigne
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <1120087131.788072.235270@g47g2000cwa.googlegroups.com>
>I'm playing with a menu system, and would like to be able to write the
>following:
>
>  (menu-item menu) -> item
>  (setf (menu-item menu) item)
>
>...
>
>Unfortunately there aren't too many online references which deal with
>DEFSETF--at least none that I've found.

Check out chapter 12 in this book. It is out of print, but available
for free online. 

http://paulgraham.com/onlisp.html
From: Kent M Pitman
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <u4qbgka9n.fsf@nhplace.com>
Robert Uhl <·········@NOSPAMgmail.com> writes:

> I'm playing with a menu system, and would like to be able to write the
> following:
> 
>   (menu-item menu) -> item
>   (setf (menu-item menu) item)
> 
> I figured that something like this would do the trick:
> 
>   (defun menu-item (menu)
>          (getf menu :title))
> 
>   (defsetf menu-title (menu) (title)
>   `(setf (getf ,menu :title) ,title))
> 
> But of course it doesn't work.  Any advice on how this needs to be
> written?

Maybe you want to call the defun menu-TITLE, not menu-ITEM?
Or you want to call the setf function menu-ITEM, not menu-TITLE?

Otherwise I don't see why it shouldn't work.

> Unfortunately there aren't too many online references which deal with
> DEFSETF--at least none that I've found.

It's not supposed to be hard.  It's like you did it, just with spelling
done right.
From: Kent M Pitman
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <uy88sih1k.fsf@nhplace.com>
Kent M Pitman <······@nhplace.com> writes:

> Robert Uhl <·········@NOSPAMgmail.com> writes:
> 
> > I'm playing with a menu system, and would like to be able to write the
> > following:
> > 
> >   (menu-item menu) -> item
> >   (setf (menu-item menu) item)
> > 
> > I figured that something like this would do the trick:
> > 
> >   (defun menu-item (menu)
> >          (getf menu :title))
> > 
> >   (defsetf menu-title (menu) (title)
> >   `(setf (getf ,menu :title) ,title))
> > 
> > But of course it doesn't work.  Any advice on how this needs to be
> > written?
> 
> Maybe you want to call the defun menu-TITLE, not menu-ITEM?
> Or you want to call the setf function menu-ITEM, not menu-TITLE?
 
[following up after private discussion between robert and me.]

Actually, this doesn't seem to be working in either LispWorks 4.4.5 
nor in SBCL 0.9.1 (I'm told).  The following results are from LW 4.4.5
after doing the obvious fix from above
 (defun menu-title (x) (getf x :title))
 (defsetf menu-title (x) (title) `(setf (getf ,x :title) ,title))

I get:

  (GET-SETF-EXPANSION '(MENU-TITLE X))
  => (#:X585),
     (X),
     (#:VALUE584),
     (SETF (GETF #:X585 :MENU-TITLE) #:VALUE584),
     (MENU-TITLE #:X585)

where I think I'd expect:

     (),
     (),
     (#:VALUE584),
     (SETF (GETF X :MENU-TITLE) #:VALUES84),
     (MENU-TITLE X)

And, even stranger, I get:

  (get-setf-expansion '(menu-title (cdr x)))
   => (#:X600),
      ((CDR X)),
      (#:VALUE599),
      (SETF (GETF #:X600 :MENU-TITLE) #:VALUE599),
      (MENU-TITLE #:X600)

when I think I'd have expected something like:

   => (#:X600),
      (X),
      (#:VALUE599),
      (SETF (GETF (CDR #:X600) :MENU-TITLE) #:VALUE599),
      (MENU-TITLE (CDR #:X600))

My sense from X3J13 issue SETF-SUB-METHODs
 [ see http://www.lispworks.com/documentation/HyperSpec/Issues/iss312.htm
   and http://www.lispworks.com/documentation/HyperSpec/Body/05_abb.htm ]
is that:

| the place referred to by place-form must always be both read and
| written; note that the update is to the generalized variable
| specified by place-form, not necessarily to the particular list that
| is the property list in question.

By this I assume that the variable X (in the first case) or the location
(CDR X) in the second case is the "place" that must "always be both read
and written", and that the list that is taken from that place is the 
"particular list that is the property list in question" which is 
"not necessarily [what is read or written]".

Does anyone else read this the same as me and agree that poor Robert is
just experiencing an implementation bug (perhaps a widespread one), or does
someone want to make the case to me that I'm reading the spec wrong.
(Note: As usual, I claim no special standing in interpreting the spec.)
From: Marco Gidde
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <lzd5q4kwjl.fsf@tristan.br-automation.de>
Kent M Pitman <······@nhplace.com> writes:

> Actually, this doesn't seem to be working in either LispWorks 4.4.5 
> nor in SBCL 0.9.1 (I'm told).  The following results are from LW 4.4.5
> after doing the obvious fix from above
>  (defun menu-title (x) (getf x :title))
>  (defsetf menu-title (x) (title) `(setf (getf ,x :title) ,title))
>
> I get:
>
>   (GET-SETF-EXPANSION '(MENU-TITLE X))
>   => (#:X585),
>      (X),
>      (#:VALUE584),
>      (SETF (GETF #:X585 :MENU-TITLE) #:VALUE584),
>      (MENU-TITLE #:X585)
>
> where I think I'd expect:
>
>      (),
>      (),
>      (#:VALUE584),
>      (SETF (GETF X :MENU-TITLE) #:VALUES84),
>      (MENU-TITLE X)
>
> And, even stranger, I get:
>
>   (get-setf-expansion '(menu-title (cdr x)))
>    => (#:X600),
>       ((CDR X)),
>       (#:VALUE599),
>       (SETF (GETF #:X600 :MENU-TITLE) #:VALUE599),
>       (MENU-TITLE #:X600)
>
> when I think I'd have expected something like:
>
>    => (#:X600),
>       (X),
>       (#:VALUE599),
>       (SETF (GETF (CDR #:X600) :MENU-TITLE) #:VALUE599),
>       (MENU-TITLE (CDR #:X600))
>
> My sense from X3J13 issue SETF-SUB-METHODs
>  [ see http://www.lispworks.com/documentation/HyperSpec/Issues/iss312.htm
>    and http://www.lispworks.com/documentation/HyperSpec/Body/05_abb.htm ]
> is that:
>
> | the place referred to by place-form must always be both read and
> | written; note that the update is to the generalized variable
> | specified by place-form, not necessarily to the particular list that
> | is the property list in question.
>
> By this I assume that the variable X (in the first case) or the location
> (CDR X) in the second case is the "place" that must "always be both read
> and written", and that the list that is taken from that place is the 
> "particular list that is the property list in question" which is 
> "not necessarily [what is read or written]".

This is true for the setf expansion of getf, but not necessarily for
menu-title. From
http://www.lispworks.com/documentation/HyperSpec/Body/m_defset.htm :

| During the evaluation of the forms, the variables in the lambda-list
| and the store-variables are bound to names of temporary variables,
| generated as if by gensym or gentemp, that will be bound by the
| expansion of setf to the values of those subforms. This binding
| permits the forms to be written without regard for
| order-of-evaluation issues. defsetf arranges for the temporary
| variables to be optimized out of the final result in cases where
| that is possible.

...

| A setf of a call on access-fn also evaluates all of access-fn's
| arguments; it cannot treat any of them specially. This means that
| defsetf cannot be used to describe how to store into a generalized
| reference to a byte, such as (ldb field
| reference). define-setf-expander is used to handle situations that
| do not fit the restrictions imposed by defsetf and gives the user
| additional control.

So I think in 

   (defsetf menu-title (x) (title) `(setf (getf ,x :title) ,title))

it looks as if we were setting X, but it's "only" a temporary bound to
X's value.


-- 
Marco Gidde
From: Robert Uhl
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <m31x6j4o2e.fsf@4dv.net>
Marco Gidde <···········@tiscali.de> writes:
>
> So I think in 
>
>    (defsetf menu-title (x) (title) `(setf (getf ,x :title) ,title))
>
> it looks as if we were setting X, but it's "only" a temporary bound to
> X's value.

That's what appears to be the problem from my POV; I replace the
interior with a PROGN containing PRINTs around the SETF, and X
definitely gets set to (:TITLE "foo"); it just doesn't effect the value
of the passed-in variable.  That is, it acts like a function, with a new
binding for a variable.

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
There is no place for nationalism in the Church.  All are one in
Christ.      --Blessed Martyr Philoumenos of Jacob's Well, +1979
From: Kent M Pitman
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <uk6kbj3q6.fsf@nhplace.com>
Marco Gidde <···········@tiscali.de> writes:

> > By this I assume that the variable X (in the first case) or the location
> > (CDR X) in the second case is the "place" that must "always be both read
> > and written", and that the list that is taken from that place is the 
> > "particular list that is the property list in question" which is 
> > "not necessarily [what is read or written]".
> 
> This is true for the setf expansion of getf, but not necessarily for
> menu-title. From
> http://www.lispworks.com/documentation/HyperSpec/Body/m_defset.htm :

Ah.  I had a feeling someone was going to dredge up something like this,
but it was late and I was too tired to look.

(It's a pity, though, because I agree it makes it more confusing.)
From: Alan Crowe
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <86zmt61f8a.fsf@cawtech.freeserve.co.uk>
Marco Gidde quoted
http://www.lispworks.com/documentation/HyperSpec/Body/m_defset.htm

     A setf of a call on access-fn also evaluates all of
     access-fn's arguments; it cannot treat any of them
     specially. This means that defsetf cannot be used to
     describe how to store into a generalized reference to a
     byte, such as (ldb field reference). define-setf-expander is
     used to handle situations that do not fit the restrictions
     imposed by defsetf and gives the user additional control.

I'm struggling with this page. What does the long form of
defsetf give you over the short form? The only advantage I
can see it that it lets you use multiple store values, for
example

* (defvar x) => X
* (defvar y) => Y

* (defsetf both nil (first-value second-value)
		`(progn (setq x ,first-value
		              y ,second-value)))
=> BOTH

* (setf (both) (values 5 7)) => 7

* (list x y) => (5 7)

But it still gives you function-like semantics, as if you
could have done 

(defun (setf both)((values first-value
                           second-value))
  (setf x first-value
        y second-value))

So (setf (menu-title menu) new-value) ends up
evaluating menu and new-value then evaluating the body of
menu-title so that the body of menu title sees the list, not
the place it came from.

OK I've got my theory: the long form of defsetf is for
multiple store values.

Problem 1: neither example uses multiple store values

Problem 2: the second example was written by Hunter
S. Thompson or William Burroughs

 (defsetf xy (&key ((x x) 0) ((y y) 0)) (store)
   `(set-xy ,store 'x ,x 'y ,y)) =>  XY
 (get-setf-expansion '(xy a b))
=>  (#:t0 #:t1),
   (a b),
   (#:store),
   ((lambda (&key ((x #:x)) ((y #:y))) 
      (set-xy #:store 'x #:x 'y #:y))
    #:t0 #:t1),
   (xy #:t0 #:t1)

One expects to see (xy 'x 17 'y 42)
This code could only run if a evalutes to x or y and b
evaluates to something we want to store.

Neither Allegro
 
(get-setf-expansion '(xy a b))
Error: keyword list (#:G22 #:G23) should only contain keys
(Y X)

nor CMUCL

(get-setf-expansion '(xy a b))

Error while parsing arguments to DEFSETF XY:
Unknown keyword: #:G861; expected one of Y, X

seems able to cope with me cutting and pasting the example
from the hyperspec.

What is the long form of defsetf for?
What is the example trying to show?

Alan Crowe
Edinburgh
Scotland
From: Kent M Pitman
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <u1x6ihyg5.fsf@nhplace.com>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> Marco Gidde quoted
> http://www.lispworks.com/documentation/HyperSpec/Body/m_defset.htm
> 
>      A setf of a call on access-fn also evaluates all of
>      access-fn's arguments; it cannot treat any of them
>      specially. This means that defsetf cannot be used to
>      describe how to store into a generalized reference to a
>      byte, such as (ldb field reference). define-setf-expander is
>      used to handle situations that do not fit the restrictions
>      imposed by defsetf and gives the user additional control.
> 
> I'm struggling with this page. What does the long form of
> defsetf give you over the short form?  The only advantage I
> can see it that it lets you use multiple store values, [...]

Well, not just this, but it also gives you syntactic convenience.
Your question is a little like "what does LAMBDA give you that DEFUN
doesn't".

> (defsetf xy (&key ((x x) 0) ((y y) 0)) (store)
>    `(set-xy ,store 'x ,x 'y ,y)) =>  XY
>  (get-setf-expansion '(xy a b))
> =>  (#:t0 #:t1),
>    (a b),
>    (#:store),
>    ((lambda (&key ((x #:x)) ((y #:y))) 
>       (set-xy #:store 'x #:x 'y #:y))
>     #:t0 #:t1),
>    (xy #:t0 #:t1)

The lambda combination in there looks wrong--that is, it looks tome
like this is probably a bug in the example in ANSI CL [not really a
hyperspec bug per se, since it just includes what ANSI CL contains].
It should presumably say either:
  ((lambda (#:x #:y) ...) #:t0 #:t1)
or
  ((lambda (&key ((x #:x)) ((y #:y))) ...) 'x #:t0 'y #:t1)
or even just 
  (let ((#:x #:t0) (#:y #:t1)) ...)

> One expects to see (xy 'x 17 'y 42)
> This code could only run if a evalutes to x or y and b
> evaluates to something we want to store.

Because the expansion given is wrong.
If the implementations have copied that wrong expansion, that's probably
why they fail, too.

> Neither Allegro
>  
> (get-setf-expansion '(xy a b))
> Error: keyword list (#:G22 #:G23) should only contain keys
> (Y X)

I think this is explained above.

> nor CMUCL
> 
> (get-setf-expansion '(xy a b))
> 
> Error while parsing arguments to DEFSETF XY:
> Unknown keyword: #:G861; expected one of Y, X

You didn't say what the expansion was for CMUCL, so it's hard to interpret
this.  The stuff returned by get-setf-expansion for pre-defined operations
is implementation-specific.

> seems able to cope with me cutting and pasting the example
> from the hyperspec.

Probably because the example is broken.  I guess you can blame me and
my proofreaders for that.  We should have caught it.

> What is the long form of defsetf for?

I think your analysis is fine.

> What is the example trying to show?

How to use it.
From: Alan Crowe
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <868y0pb41k.fsf@cawtech.freeserve.co.uk>
Kent M Pitman wrote:
> > What is the long form of defsetf for?
>
>I think your analysis is fine.

Thank you. I was getting worried there.

What I found really eye catching was the use of non-keyword
keyword-names

    (lambda (&key ((x x))...

I imagine that if you use them, you risk being seduced by the
dark side of the parentheses and would start writing code
such as

* (defun abuse-keys (&key ((x v1) 'apple)
			  ((a v2) 'banana))
    (format t "~&first ~A, then ~A." v1 v2))

* (defvar x 'a)

* (progn (abuse-keys 'x 'carrot)
	 (abuse-keys x 'damson))

first CARROT, then BANANA.
first APPLE, then DAMSON.

So what were they doing in code that was meant to exemplify
defsetf?

Now that I've slept on it, it occurs to me that you cannot
play that particular game with a macro lambda list. Since
the arguments are taken literally. X represents the key X
and 'X isn't a symbol so doesn't work at all.

So perhaps the author of the example decided to play games
with non-keyword keyword-name because that would point up
the fact that a defsetf lambda list is like an ordinary
lambda list. If so, then the example was relevant to the
original posters problem, which centered on MENU being
evaluated, with the result that GETF only go to see the
list, not the place it was stored.

Alan Crowe
Edinburgh
Scotland
From: Peder O. Klingenberg
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <ksslz0iaoh.fsf@beto.netfonds.no>
Robert Uhl <·········@NOSPAMgmail.com> writes:

>   (defsetf menu-title (menu) (title)
>   `(setf (getf ,menu :title) ,title))

I've never been able to grok defsetf.  But I find that for my uses,
(defun (setf ...) ...) has always done the trick.

As an example, I have an application that makes extensive use of a
cache of data, contained in a data structure built up of nested hashes
(yes, I've been a perl programmer).

The handling of the nested hashes are in a package of its own, but to
save some typing in my application, I defined the following two
functions.

   (defun cache-get (&rest keys)
     (nh:nhget keys *portfolio-cache*))

   (defun (setf cache-get) (newval &rest keys)
     (setf (nh:nhget keys *portfolio-cache*) newval))

This allows me to write things like

   (cache-get :traversal :path through :tree) => value1
   (setf (cache-get :traversal :path through :tree) value2) => value2

This works flawlessly, at least in lispworks 4.3.

(As you may infer, the nested hash package contains its own 
(defun (setf nhget) ...), but its definition is rather more complex.)

...Peder...
-- 
This must be Thursday.  I never could get the hang of Thursdays.
From: Kent M Pitman
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <u8y0s1ewp.fsf@nhplace.com>
·····@news.klingenberg.no (Peder O. Klingenberg) writes:

> I've never been able to grok defsetf.  But I find that for my uses,
> (defun (setf ...) ...) has always done the trick.

The reason this works for you is not that you're using (defun (setf...) ...)
but that the argument you are passing contains an adequate pointer to reliably
update the object.  That is, if you pass a hash table, you can update the
hash table reliably.  But if you pass a list, you cannot reliably update the
list since, worst case, the list might be NIL and there is no way to grow NIL
to contain elements by side-effect--NIL cannot be side-effected.

Robert's problem is that he's trying to side-effect the object, which I claim
_should_ work if defsetf were doing what I think it should do, recursively
interpreting a place within a place subform so that it gets updated right.
(I might be wrong and I'm waiting for others to chime in with opinions.)

But in any case, the workaround is instead of passing a list to either pass
the result of (CONS something data-you-care-about) so that you can GETF its
cdr, and then you have something to update when the cdr is NIL, or else to
pass a hashtable (which updates something internal pointed to by the hashtable,
not the hashtable itself, or to pass something else like a struct with
 (DEFSTRUCT MENU
   (PLIST '()))
so that you can do 
 (defun menu-title (menu) (getf (menu-plist menu) :title))
 (defsetf menu-title (menu) (title)
   `(setf (getf (menu-plist ,menu) :title) ,title))

This will work if you do
 (defun (setf menu-title) (title menu)
   (setf (getf (menu-plist menu) :title) title))
also, but what won't work is
 (defun menu-title (menu) (getf menu :title))
 (defun (setf menu-title) (title menu) (setf (getf menu :title) title))
because there if you do (setq x nil) (setf (menu-title x) "foo")
you're just going to do (funcall #'(setf menu-title) NIL "foo") and that
is just never powerful enough to update X from within (setf menu-title),
since it gets no pointer to X, it only gets a pointer to NIL (X's content).
From: Peder O. Klingenberg
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <ksmzp8i8pd.fsf@beto.netfonds.no>
Kent M Pitman <······@nhplace.com> writes:

> The reason this works for you is not that you're using (defun (setf...) ...)
> but that the argument you are passing contains an adequate pointer to reliably
> update the object.

Thanks.  I see the distinction now, I think, and my head doesn't even
hurt yet. :)

...Peder...
-- 
This must be Thursday.  I never could get the hang of Thursdays.
From: Frode Vatvedt Fjeld
Subject: Re: Canonical Way to Mask SETF?
Date: 
Message-ID: <2hr7ejlieb.fsf@vserver.cs.uit.no>
Robert Uhl <·········@NOSPAMgmail.com> writes:

>   (defun menu-item (menu)
>          (getf menu :title))
>
>   (defsetf menu-title (menu) (title)
>   `(setf (getf ,menu :title) ,title))
>
> But of course it doesn't work.  Any advice on how this needs to be
> written?

One possibility is simply:

  (defmacro menu-item (menu) `(getf ,menu :title))

Now both the setter and getter should work as expected. You don't get
(function menu-item), but then again there's clearly no way you can
get (function (setf menu-item)), so maybe that's reasonable.

-- 
Frode Vatvedt Fjeld