From: Giorgos Pontikakis
Subject: difference between defsetf and defun (setf ...)
Date: 
Message-ID: <87odtwdhjp.fsf@artemis.extherm.gr>
Hello all,

I wonder if there is a difference (substantial or stylistic) between
using:

(defsetf (name) ...)

and 

(defun (setf name) ...).

apart from the fact that the syntax is somewhat different.

Should I prefer any of the two forms in certain contexts? Are there
situations where one is prefferable over the other? Which is more
common/idiomatic to use?

Thanks,

-- Giorgos

From: Stephen Compall
Subject: Re: difference between defsetf and defun (setf ...)
Date: 
Message-ID: <JSEKg.335204$zw6.209386@fe02.news.easynews.com>
Giorgos Pontikakis wrote:
> I wonder if there is a difference (substantial or stylistic) between
> using:
> 
> (defsetf (name) ...)
> 
> and 
> 
> (defun (setf name) ...).
> 
> apart from the fact that the syntax is somewhat different.
> 
> Should I prefer any of the two forms in certain contexts? Are there
> situations where one is prefferable over the other?

The short-form DEFSETF and DEFUN on SETF are more-or-less equivalent;
they both store a setter function at (fdefinition (setf name)) and
define appropriate setf-expanders.

Use the long form of DEFSETF, which is quite different from the two
preceding forms, when those won't work.  Use DEFINE-SETF-EXPANDER when
long-form DEFSETF won't work.

> Which is more common/idiomatic to use?

I prefer short-form DEFSETF over DEFUN on SETF, but most will likely
disagree.  Know when you need the capabilities of the other two
options, however.

-- 
Stephen Compall
http://scompall.nocandysw.com/blog
From: Giorgos Pontikakis
Subject: Re: difference between defsetf and defun (setf ...)
Date: 
Message-ID: <87mz9g93s5.fsf@artemis.extherm.gr>
Stephen Compall <···············@gmail.com> writes:

> Giorgos Pontikakis wrote:
>> I wonder if there is a difference (substantial or stylistic) between
>> using:
>> 
>> (defsetf (name) ...)
>> 
>> and 
>> 
>> (defun (setf name) ...).
>> 
>> apart from the fact that the syntax is somewhat different.
>> 
>> Should I prefer any of the two forms in certain contexts? Are there
>> situations where one is prefferable over the other?
>
> The short-form DEFSETF and DEFUN on SETF are more-or-less equivalent;
> they both store a setter function at (fdefinition (setf name)) and
> define appropriate setf-expanders.
>
> Use the long form of DEFSETF, which is quite different from the two
> preceding forms, when those won't work.  Use DEFINE-SETF-EXPANDER when
> long-form DEFSETF won't work.
>
Could you please elaborate on this?  I thought that the long form of
DEFSETF is _similar_ to the DEFUN on SETF.

To be specific with my problem:

For learning purposes, I have a function named ENTRY which is
more or less identical to GETHASH. 

(defun entry (table &optional key)
  (cond
    ;; if key is nil, return a list of all entries
    ((null key) (let ((entry-list nil))
		  (maphash #'(lambda (k e)
			       (declare (ignore k))
			       (push e entry-list))
			   table)
		  entry-list))
    ;; otherwise, return entry normally
    (t (gethash key table))))

Then I can do the following:

Either:

(defun (setf entry) (new-val table key)
  (setf (gethash key table) new-val)
   new-val)

or:

(defsetf entry (table key) (new-val)
  `(progn (setf (gethash ,key ,table) ,new-val)
	  ,new-val))

This prompted my original post -- I could not decide which is
better. Sorry for not being specific from the beginning.


>> Which is more common/idiomatic to use?
>
> I prefer short-form DEFSETF over DEFUN on SETF, but most will likely
> disagree.  Know when you need the capabilities of the other two
> options, however.

Furthermore, I am too new to lisp to be able to imagine a situation
where DEFSETF is not adequate and I have to resort to
DEFINE-SETF-EXPANDER :-). If you could give an example or a relevant link,
I would be grateful.
>
> -- 
> Stephen Compall
> http://scompall.nocandysw.com/blog

Thank you very much,

-- Giorgos
From: Pascal Bourguignon
Subject: Re: difference between defsetf and defun (setf ...)
Date: 
Message-ID: <87d5aclfov.fsf@thalassa.informatimago.com>
Giorgos Pontikakis <···@freemail.gr> writes:
> For learning purposes, I have a function named ENTRY which is
> more or less identical to GETHASH. 
>
> (defun entry (table &optional key)
>   (cond
>     ;; if key is nil, return a list of all entries
>     ((null key) (let ((entry-list nil))

Bad Giorgos! 

 (defun entry (table &optional (key nil keyp))
   (cond
     ;; if key is not provided, return a list of all entries
     ((not keyp) (let ((entry-list nil))


So you can write:

(setf (entry negation t)   nil
      (entry negation nil) t)


> 		  (maphash #'(lambda (k e)
> 			       (declare (ignore k))
> 			       (push e entry-list))
> 			   table)
> 		  entry-list))
>     ;; otherwise, return entry normally
>     (t (gethash key table))))
>
> Then I can do the following:
>
> Either:
>
> (defun (setf entry) (new-val table key)
>   (setf (gethash key table) new-val)
>    new-val)
>
> or:
>
> (defsetf entry (table key) (new-val)
>   `(progn (setf (gethash ,key ,table) ,new-val)
> 	  ,new-val))

Try: 
     (let ((val 1))
       (print (setf (entry table :key) (incf val)))
       val)

(defsetf entry (table key) (new-val)
   (let ((vval (gensym "NEWVAL")))
     `(let ((,vval ,new-val))
         (setf (gethash ,key ,table) ,vval)
 	    ,vval)))

is slightly better, but there is still a problem:

   (let ((val 1))
      (setf (entry (aref tables (incf val)) (incf val)) (incf val))
      ; should be doing:  (setf (entry (aref table 2) 3) 4)
      ; but instead does: (setf (entry (aref table 4) 3) 2)
      )

Usually, you should keep the "standard" order of evaluation:

(defsetf entry (table key) (new-val)
   (let ((vtable (gensym "TABLE"))
         (vkey   (gensym "KEY"))
         (vval   (gensym "NEWVAL")))
     `(let ((,vtable ,table)
            (,vkey   ,key)
            (,vval   ,new-val))
         (setf (gethash ,vkey ,vtable) ,vval))))
       ;; setf returns the last values assigned.

This is a sign that you don't need a macro.  The (defun (setf entry) ...) 
form is more correct.


> This prompted my original post -- I could not decide which is
> better. Sorry for not being specific from the beginning.

For simple cases such as this one, they're functionnaly equivalent (as
long as you comply with the expected semantics).
See: CLHS 5.1.1.1 Evaluation of Subforms to Places


>>> Which is more common/idiomatic to use?
>>
>> I prefer short-form DEFSETF over DEFUN on SETF, but most will likely
>> disagree.  Know when you need the capabilities of the other two
>> options, however.
>
> Furthermore, I am too new to lisp to be able to imagine a situation
> where DEFSETF is not adequate and I have to resort to
> DEFINE-SETF-EXPANDER :-). If you could give an example or a relevant link,
> I would be grateful.

For example,

(let ((string (format nil "Good bye, xxxxx world!")))
  (setf (subseq string 10 15) "cruel")
  string)

--> "Good bye, cruel world!"

You won't be able to write a
  (defun (setf subseq) (value string start end) ...)
that will be able to modify the string variable, because
arguments are passed by value.


Sorry I don't have an example where define-setf-expander is needed. 
On the other hand, get-setf-expander is good to implement correctly 
some macros like POP.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Indentation! -- I will show you how to indent when I indent your skull!"
From: Giorgos Pontikakis
Subject: Re: difference between defsetf and defun (setf ...)
Date: 
Message-ID: <873bb7igpc.fsf@artemis.extherm.gr>
Pascal Bourguignon <···@informatimago.com> writes:

> Giorgos Pontikakis <···@freemail.gr> writes:
>> For learning purposes, I have a function named ENTRY which is
>> more or less identical to GETHASH. 
>>
>> (defun entry (table &optional key)
>>   (cond
>>     ;; if key is nil, return a list of all entries
>>     ((null key) (let ((entry-list nil))
>
> Bad Giorgos! 
>
>  (defun entry (table &optional (key nil keyp))
>    (cond
>      ;; if key is not provided, return a list of all entries
>      ((not keyp) (let ((entry-list nil))
>
>
> So you can write:
>
> (setf (entry negation t)   nil
>       (entry negation nil) t)
>
>
>> 		  (maphash #'(lambda (k e)
>> 			       (declare (ignore k))
>> 			       (push e entry-list))
>> 			   table)
>> 		  entry-list))
>>     ;; otherwise, return entry normally
>>     (t (gethash key table))))
>>

Ok, that was really bad! Thank you. I remember reading about this
syntax in Seibel's book, but I then forgot it completely.

>> Then I can do the following:
>>
>> Either:
>>
>> (defun (setf entry) (new-val table key)
>>   (setf (gethash key table) new-val)
>>    new-val)
>>
>> or:
>>
>> (defsetf entry (table key) (new-val)
>>   `(progn (setf (gethash ,key ,table) ,new-val)
>> 	  ,new-val))
>
> Try: 
>      (let ((val 1))
>        (print (setf (entry table :key) (incf val)))
>        val)
>
> (defsetf entry (table key) (new-val)
>    (let ((vval (gensym "NEWVAL")))
>      `(let ((,vval ,new-val))
>          (setf (gethash ,key ,table) ,vval)
>  	    ,vval)))
>
> is slightly better, but there is still a problem:
>
>    (let ((val 1))
>       (setf (entry (aref tables (incf val)) (incf val)) (incf val))
>       ; should be doing:  (setf (entry (aref table 2) 3) 4)
>       ; but instead does: (setf (entry (aref table 4) 3) 2)
>       )
>
> Usually, you should keep the "standard" order of evaluation:
>
> (defsetf entry (table key) (new-val)
>    (let ((vtable (gensym "TABLE"))
>          (vkey   (gensym "KEY"))
>          (vval   (gensym "NEWVAL")))
>      `(let ((,vtable ,table)
>             (,vkey   ,key)
>             (,vval   ,new-val))
>          (setf (gethash ,vkey ,vtable) ,vval))))
>        ;; setf returns the last values assigned.
>

I don't get this. I read the Hyperspec section about DEFSETF and it says:

"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"

I suppose that this also protects me from multiple evaluation of the
macro arguments. Indeed, in my lisp (sbcl on linux) I get:

CL-USER> (defparameter *my-table* (make-hash-table))
*MY-TABLE*
CL-USER> (let ((val 1))
	   (print (setf (entry *my-table* :key) (incf val)))
	   val)

2 
2
CL-USER> (entry *my-table* :key)
2
T

This is what I expected. Also:

CL-USER> (let ((val 0))
	   (setf (entry *my-table* (incf val)) (incf val)))
2
CL-USER> (entry *my-table* 1)
2
T

I hope that I am not totally confused. I suppose I misunderstand your
comment. Could you explain further?


> This is a sign that you don't need a macro.  The (defun (setf entry) ...) 
> form is more correct.
>
>
>> This prompted my original post -- I could not decide which is
>> better. Sorry for not being specific from the beginning.
>
> For simple cases such as this one, they're functionnaly equivalent (as
> long as you comply with the expected semantics).
> See: CLHS 5.1.1.1 Evaluation of Subforms to Places
>
>
>>>> Which is more common/idiomatic to use?
>>>
>>> I prefer short-form DEFSETF over DEFUN on SETF, but most will likely
>>> disagree.  Know when you need the capabilities of the other two
>>> options, however.
>>
>> Furthermore, I am too new to lisp to be able to imagine a situation
>> where DEFSETF is not adequate and I have to resort to
>> DEFINE-SETF-EXPANDER :-). If you could give an example or a relevant link,
>> I would be grateful.
>
> For example,
>
> (let ((string (format nil "Good bye, xxxxx world!")))
>   (setf (subseq string 10 15) "cruel")
>   string)
>
> --> "Good bye, cruel world!"
>
> You won't be able to write a
>   (defun (setf subseq) (value string start end) ...)
> that will be able to modify the string variable, because
> arguments are passed by value.

Hmm, looks like a nice exercise. I will try to implement this with
defsetf or def-setf-expander and report the results .

Anyway, thank you very much both of you for the responses.

Best regards,

-- Giorgos
From: Pascal Bourguignon
Subject: Re: difference between defsetf and defun (setf ...)
Date: 
Message-ID: <87r6yr9zwr.fsf@thalassa.informatimago.com>
Giorgos Pontikakis <···@freemail.gr> writes:

> Pascal Bourguignon <···@informatimago.com> writes:
>> Usually, you should keep the "standard" order of evaluation:
>>
>> (defsetf entry (table key) (new-val)
>>    (let ((vtable (gensym "TABLE"))
>>          (vkey   (gensym "KEY"))
>>          (vval   (gensym "NEWVAL")))
>>      `(let ((,vtable ,table)
>>             (,vkey   ,key)
>>             (,vval   ,new-val))
>>          (setf (gethash ,vkey ,vtable) ,vval))))
>>        ;; setf returns the last values assigned.
>>
>
> I don't get this. I read the Hyperspec section about DEFSETF and it says:
>
> "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"
>
> I suppose that this also protects me from multiple evaluation of the
> macro arguments. Indeed, in my lisp (sbcl on linux) I get:

My bad.  I overlooked this. Indeed, defsetf do it for you, so we don't
have to do it.  Sorry.


   (defsetf entry (table key) (new-val)
     `(setf (gethash ,key ,table) ,new-val))

should be all that is needed. (setf returns the last values assigned).


> I hope that I am not totally confused. I suppose I misunderstand your
> comment. Could you explain further?

Sorry, it was me who was confused :-(



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
I need a new toy.
Tail of black dog keeps good time.
Pounce! Good dog! Good dog!
From: Stephen Compall
Subject: Re: difference between defsetf and defun (setf ...)
Date: 
Message-ID: <InNKg.563992$bN2.79963@fe09.news.easynews.com>
Giorgos Pontikakis wrote:
> Furthermore, I am too new to lisp to be able to imagine a situation
> where DEFSETF is not adequate and I have to resort to
> DEFINE-SETF-EXPANDER :-). If you could give an example or a relevant link,
> I would be grateful.

Mr. Bourguignon has already written on the preference for functional
forms over the long-form DEFSETF.

Long-form DEFSETF is like DEFINE-SETF-EXPANDER, except that it hides
the actual form arguments passed as part of the form being set behind
uninterned symbols, and you only need compute and answer the fourth
value of the expansion.  TEMPS, TEMP-VALS, STORE-VARS, and ACCESS-FORM
are precomputed and answered for you in the manner you'd expect when
writing a standard setf-expansion for a normal function.

Some functions have special needs; for example, LDB's setf-expander
modifies its integer argument.  The setf-expander for VALUES must vary
its STORE-VARS.  For these to happen, you need full control over the
setf expansion.

http://scompall.nocandysw.com/_local/association.lisp is an example I
wrote recently.  It uses extra TEMPS, extra and special TEMP-VALS (so
it follows), and a special ACCESS-FORM.  It needs special
setf-expansion in order to be able to treat its alist argument as a
place, rather than just a value, as with LDB.

If you are looking for an exercise in deciphering setf expanders, add
support for ASSOC's keyword arguments to the ASSOCIATION function and
its setf-expander; you should only have to add one variable reference
to the latter form.

-- 
Stephen Compall
http://scompall.nocandysw.com/blog