From: V. Rotaru
Subject: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <87is647w9z.fsf@localhost.localdomain>
Hello all.

This works, how I expect it to work:

(defvar *damn-my-cats-hash* (make-hash-table))

(defun retrieve (key)
   (gethash key *damn-my-cats-hash*))

(defun retrieve-setf (key val)
  (setf (gethash key *damn-my-cats-hash*) val))

(defsetf retrieve retrieve-setf)

(progn (setf (retrieve :foo) 42) (retrieve :foo)) => 42, T

And this does not:

(defun retrieve2 (key)
   (gethash key *damn-my-cats-hash*))

(defun (setf retrieve2) (key val)
  (setf (gethash key *damn-my-cats-hash*) val))

(progn (setf (retrieve2 :bar) 42) (retrieve2 :bar)) => NIL, NIL

and 

(retrieve2 42) => :BAR, T

Curioser, and curiosier. Should I then write

(defun (setf retrieve2) (val key) ...)

Why?


-- 
                                                     If in doubt, mumble.

From: jtdubs
Subject: Re: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <1105398168.653370.239930@f14g2000cwb.googlegroups.com>
V. Rotaru wrote:
> Hello all.
>
> This works, how I expect it to work:
>
> (defvar *damn-my-cats-hash* (make-hash-table))
>
> (defun retrieve (key)
>    (gethash key *damn-my-cats-hash*))
>
> (defun retrieve-setf (key val)
>   (setf (gethash key *damn-my-cats-hash*) val))
>
> (defsetf retrieve retrieve-setf)
>
> (progn (setf (retrieve :foo) 42) (retrieve :foo)) => 42, T
>
> And this does not:
>
> (defun retrieve2 (key)
>    (gethash key *damn-my-cats-hash*))
>
> (defun (setf retrieve2) (key val)
>   (setf (gethash key *damn-my-cats-hash*) val))
>
> (progn (setf (retrieve2 :bar) 42) (retrieve2 :bar)) => NIL, NIL
>
> and
>
> (retrieve2 42) => :BAR, T
>
> Curioser, and curiosier. Should I then write
>
> (defun (setf retrieve2) (val key) ...)
>
> Why?

Consider:

(defun get-car (cons-cell &optional actually-i-want-the-cdr-p)
(if actually-i-want-the-cdr-p
(cdr cons-cell)
(car cons-cell)))

(defun (setf get-car) (new-value cons-cell &optional
actually-i-want-the-cdr-p)
(if actually-i-want-the-cdr-p
(setf (cdr cons-cell) new-value)
(setf (car cons-cell) new-value)))

And:

(defun my-aref (array x y)
(aref array x y))

(defun (setf my-aref) (new-value array x y)
(setf (aref array x y) new-value))

Basically, the (defun (setf ...) ...) form has the same parameters as
the accessor function, except the new-value is prepended to it.  You
can't append the new-value parameter because of optional parameters and
keyword parameters.

Justin Dubs
From: Andreas Thiele
Subject: Re: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <crv26l$854$05$1@news.t-online.com>
"jtdubs" <······@eos.ncsu.edu> schrieb im Newsbeitrag
·····························@f14g2000cwb.googlegroups.com...
> V. Rotaru wrote:
> > Hello all.
> >
> > This works, how I expect it to work:
> >
> > (defvar *damn-my-cats-hash* (make-hash-table))
> >
> > (defun retrieve (key)
> >    (gethash key *damn-my-cats-hash*))
> >
> > (defun retrieve-setf (key val)
> >   (setf (gethash key *damn-my-cats-hash*) val))
> >
> > (defsetf retrieve retrieve-setf)
> >
> > (progn (setf (retrieve :foo) 42) (retrieve :foo)) => 42, T
> >
> > And this does not:
> >
> > (defun retrieve2 (key)
> >    (gethash key *damn-my-cats-hash*))
> >
> > (defun (setf retrieve2) (key val)
> >   (setf (gethash key *damn-my-cats-hash*) val))
> >
> > (progn (setf (retrieve2 :bar) 42) (retrieve2 :bar)) => NIL, NIL
> >
> > and
> >
> > (retrieve2 42) => :BAR, T
> >
> > Curioser, and curiosier. Should I then write
> >
> > (defun (setf retrieve2) (val key) ...)
> >
> > Why?
>
> Consider:
>
> (defun get-car (cons-cell &optional actually-i-want-the-cdr-p)
> (if actually-i-want-the-cdr-p
> (cdr cons-cell)
> (car cons-cell)))
>
> (defun (setf get-car) (new-value cons-cell &optional
> actually-i-want-the-cdr-p)
> (if actually-i-want-the-cdr-p
> (setf (cdr cons-cell) new-value)
> (setf (car cons-cell) new-value)))
>
> And:
>
> (defun my-aref (array x y)
> (aref array x y))
>
> (defun (setf my-aref) (new-value array x y)
> (setf (aref array x y) new-value))
>
> Basically, the (defun (setf ...) ...) form has the same parameters as
> the accessor function, except the new-value is prepended to it.  You
> can't append the new-value parameter because of optional parameters and
> keyword parameters.
>
> Justin Dubs
>

OK, I understand - but why is the short form of defsetf explicitely defined
the other way around?

Andreas
From: jtdubs
Subject: Re: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <1105400527.650339.33270@c13g2000cwb.googlegroups.com>
Andreas Thiele wrote:
> "jtdubs" <······@eos.ncsu.edu> schrieb im Newsbeitrag
> ·····························@f14g2000cwb.googlegroups.com...
> > V. Rotaru wrote:
> > > Hello all.
> > >
> > > This works, how I expect it to work:
> > >
> > > (defvar *damn-my-cats-hash* (make-hash-table))
> > >
> > > (defun retrieve (key)
> > >    (gethash key *damn-my-cats-hash*))
> > >
> > > (defun retrieve-setf (key val)
> > >   (setf (gethash key *damn-my-cats-hash*) val))
> > >
> > > (defsetf retrieve retrieve-setf)
> > >
> > > (progn (setf (retrieve :foo) 42) (retrieve :foo)) => 42, T
> > >
> > > And this does not:
> > >
> > > (defun retrieve2 (key)
> > >    (gethash key *damn-my-cats-hash*))
> > >
> > > (defun (setf retrieve2) (key val)
> > >   (setf (gethash key *damn-my-cats-hash*) val))
> > >
> > > (progn (setf (retrieve2 :bar) 42) (retrieve2 :bar)) => NIL, NIL
> > >
> > > and
> > >
> > > (retrieve2 42) => :BAR, T
> > >
> > > Curioser, and curiosier. Should I then write
> > >
> > > (defun (setf retrieve2) (val key) ...)
> > >
> > > Why?
> >
> > Consider:
> >
> > (defun get-car (cons-cell &optional actually-i-want-the-cdr-p)
> > (if actually-i-want-the-cdr-p
> > (cdr cons-cell)
> > (car cons-cell)))
> >
> > (defun (setf get-car) (new-value cons-cell &optional
> > actually-i-want-the-cdr-p)
> > (if actually-i-want-the-cdr-p
> > (setf (cdr cons-cell) new-value)
> > (setf (car cons-cell) new-value)))
> >
> > And:
> >
> > (defun my-aref (array x y)
> > (aref array x y))
> >
> > (defun (setf my-aref) (new-value array x y)
> > (setf (aref array x y) new-value))
> >
> > Basically, the (defun (setf ...) ...) form has the same parameters
as
> > the accessor function, except the new-value is prepended to it.
You
> > can't append the new-value parameter because of optional parameters
and
> > keyword parameters.
> >
> > Justin Dubs
> >
>
> OK, I understand - but why is the short form of defsetf explicitely
defined
> the other way around?

I'm not sure.  Bare in mind that defsetf is just a convenience macro
which expands to a call to define-setf-expander.  As the order (key
new-value) seems more intuitive than (new-value key), I think it makes
sense to choose that order for the simplified interface.

Justin Dubs
From: Steven M. Haflich
Subject: Re: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <06KEd.10215$5R.3864@newssvr21.news.prodigy.com>
jtdubs wrote:

> I'm not sure.  Bare in mind that defsetf is just a convenience macro
> which expands to a call to define-setf-expander.

I see no justification in the ANS for the above statement, not that it
makes any semantic difference to the rest of your argument.

> As the order (key
> new-value) seems more intuitive than (new-value key), I think it makes
> sense to choose that order for the simplified interface.

I think rather that in the simple form of setf the setter function can
simply be substituted in the calling form, as

  (defsetf foo foo-steer)
  (setf (foo . args) newval)  ==>  (foo-setter ,@args newval)

which preserves the order of evaluation expressed in the original code.
If it were the other way around the setf expansion would necessitate all
the get-setf-expansion and temporary variable bindings of he full
setf machinery (to preserve the order of evaluation of subforms, which
setf guarantees).

Nowadays, many compilers would generate essentially the same code for
these two expansions.  But long ago compilers were less smart, like C
programmers are still less smart, and use intermediate storage for
local variables.  Modern compilers know that local variables are merely
names atacked to the values of computations to communicate those values
to other places in the computation.  But I believe it was not always so
in the early days when experiments were adding setf to the language.
From: jtdubs
Subject: Re: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <1105456010.073988.305020@f14g2000cwb.googlegroups.com>
Steven M. Haflich wrote:
> jtdubs wrote:
>
> > I'm not sure.  Bare in mind that defsetf is just a convenience
macro
> > which expands to a call to define-setf-expander.
>
> I see no justification in the ANS for the above statement, not that
it
> makes any semantic difference to the rest of your argument.

Yep, you're right.  I saw the "(See define-setf-expander for more
general access to this facility.)" note and just assumed the rest, but
it could clearly expand to something else entirely.

> > As the order (key
> > new-value) seems more intuitive than (new-value key), I think it
makes
> > sense to choose that order for the simplified interface.
>
> I think rather that in the simple form of setf the setter function
can
> simply be substituted in the calling form, as
>
>   (defsetf foo foo-steer)
>   (setf (foo . args) newval)  ==>  (foo-setter ,@args newval)
>
> which preserves the order of evaluation expressed in the original
code.
> If it were the other way around the setf expansion would necessitate
all
> the get-setf-expansion and temporary variable bindings of he full
> setf machinery (to preserve the order of evaluation of subforms,
which
> setf guarantees).
>
> Nowadays, many compilers would generate essentially the same code for
> these two expansions.  But long ago compilers were less smart, like C
> programmers are still less smart, and use intermediate storage for
> local variables.  Modern compilers know that local variables are
merely
> names atacked to the values of computations to communicate those
values
> to other places in the computation.  But I believe it was not always
so
> in the early days when experiments were adding setf to the language.
Ah, i see.  I like this answer much better.  Thank you.

Justin Dubs
From: Peter Seibel
Subject: Re: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <m3vfa4ga0n.fsf@javamonkey.com>
··@localhost.localdomain (V. Rotaru) writes:

> Hello all.
>
> This works, how I expect it to work:
>
> (defvar *damn-my-cats-hash* (make-hash-table))
>
> (defun retrieve (key)
>    (gethash key *damn-my-cats-hash*))
>
> (defun retrieve-setf (key val)
>   (setf (gethash key *damn-my-cats-hash*) val))
>
> (defsetf retrieve retrieve-setf)
>
> (progn (setf (retrieve :foo) 42) (retrieve :foo)) => 42, T
>
> And this does not:
>
> (defun retrieve2 (key)
>    (gethash key *damn-my-cats-hash*))
>
> (defun (setf retrieve2) (key val)
>   (setf (gethash key *damn-my-cats-hash*) val))
>
> (progn (setf (retrieve2 :bar) 42) (retrieve2 :bar)) => NIL, NIL
>
> and 
>
> (retrieve2 42) => :BAR, T
>
> Curioser, and curiosier. Should I then write
>
> (defun (setf retrieve2) (val key) ...)
>
> Why?

Because the value being assigned is always the first argument to a
SETF function. So why is that? At some level that's just the way it
is. But it does makes a certain amount of sense when you consider that
some SETF functions require more than one argument to identify the
place. For instance when you SETF AREF of a multi-dimensional array
like this:

  (setf (aref array 0 1 0 2) 'something)

the SETF function needs to be passed 'something, array, 0, 1, 0, and
2. But the number of arguments depend on the dimensionality of the
array. By making the new value the first argument the SETF function
for AREF can be defined something like this:

  (defun (setf aref) (new-value array &rest indices) ...)

If the new-value was the last argument you'd have to write it like
this:

  (defun (setf aref) (array &rest indices-and-new-value)
    (let ((indices (butlast indices-and-new-value))
          (new-value (first (last indices-and-new-value))))
      ...))

-Peter  

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Frode Vatvedt Fjeld
Subject: Re: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <2hbrbwhoeh.fsf@vserver.cs.uit.no>
··@localhost.localdomain (V. Rotaru) writes:

> Curioser, and curiosier. Should I then write
>
> (defun (setf retrieve2) (val key) ...)

Yes. The value is the first argument presented to setf functions.

> Why?

Because the "place" defined by the setf function can have zero or more
sub-forms--they don't necessarily have exactly one sub-form as in your
example. Therefore, the function mus be presented with one argument
which is the new value for the place, and zero or more arguments that
are the results of evaluating the sub-forms. A lot of things would get
really complicated and awkward if the value argument was to be the
last argument given to the setf function (just think if the place has
optional or keyword arguments..)

For example, if your example used two keys instead of one, and one
optional keyword key, you'd get

  (defun retrieve3 (key1 key2 &key (extra-key 42)) ...)

now, if the value argument was to be the last argument to the setf
function, what would its signature be? In short, we avoid a lot of
funny rules by always having the value argument be the first one, like
so:

  (define (setf retrieve3) (value key1 key2 &key (extra-key 42))
     ...)

Note however that the order of evaluation is kept left-to-right as
usual, so that in the form

  (setf (retrieve3 (my-key1) (my-key2) :extra-key (hubba)) (my-secret))

the order is such that the forms (my-key1), (my-key2), (hubba), and
(my-secret) are evaluated in that order, as you'd expect.

If you're interested, this is typically done by the lisp system by
having the setf form expanded to something to the effect of this (just
try it with (macroexpand-1 '(setf (retrieve ..) 'foo)) !):

  (let ((x (my-key1))
        (y (my-key2))
        (k :extra-key)
        (z (hubba)))
    (funcall #'(setf retrieve3) (my-secret) x y k z))

-- 
Frode Vatvedt Fjeld
From: From  V. Rotaru
Subject: Re: Q. about (defun (setf ..) ..)
Date: 
Message-ID: <877jmk7t5w.fsf@localhost.localdomain>
Frode Vatvedt Fjeld <······@cs.uit.no> writes:

> ··@localhost.localdomain (V. Rotaru) writes:
> 
> > Curioser, and curiosier. ...

Thank you and others for the quick and to the point answers. Now I see
the *why*, and it make sense.

-- 
                                                     If in doubt, mumble.