From: David Bakhash
Subject: DEFINE-MODIFY-MACRO usage question
Date: 
Message-ID: <m366hymhc0.fsf@cadet.dsl.speakeasy.net>
a while back, the following code was posted.  If it helps, think of
`drop' as a `deletef', if one existed.

(defmacro drop (object place &rest keys &key key test test-not &environment environment)
  "Drop a particular OBJECT from list in PLACE.  (Intended as counterpart to PUSH/-NEW.)
Copyright 1999 by Erik Naggum.  Verbatim inclusion and redistribution permitted.
For any other use, write <····@naggum.no> or call +47 8800 8879 or +1 510 435 8604."
  (declare (ignore key test test-not))
  (multiple-value-bind (vars vals store-vars writer reader)
      (get-setf-expansion place environment)
    (let ((evaled-value (gensym))
	  (store-var (first store-vars)))
      (if (cdr store-vars)
	`(let* ((,evaled-value ,object)
		,@(mapcar #'list vars vals))
	   (multiple-value-bind ,store-vars ,reader
	     (setq ,store-var (delete ,evaled-value ,store-var :count 1 ,@keys))
	     ,writer))
	`(let* ((,evaled-value ,object)
		,@(mapcar #'list vars vals)
		(,store-var (delete ,evaled-value ,reader :count 1 ,@keys)))
	   ,writer)))))

I recently wanted similar functionality to that (basically, I wanted a
DELETEF macro).  I wrote the one below, and wanted to compare it with
the implementation above.

My implementation is as follows:

(defun delete* (list elt &rest args)
  (apply #'delete elt list args))

(define-modify-macro delete*f (&rest args)
  delete*)

(defmacro deletef (elt list &rest args)
  `(delete*f ,list ,elt ,@args))

I wrote it like that (i.e. with the nasty delete*f) because I wanted
to preserve the order that delete used in the new deletef, and I
wasn't aware of another way.

The reason I wasn't sure I'd rather use GET-SETF-EXPANSION here is
that environment argument, which I don't feel belongs here, and I
avoided with define-modify-macro, whereas the DROP implementation
accepts the environment keyword argument, I'm guessing that
DEFINE-MODIFY-MACRO bypasses that, somehow.

feedback appreciated,
dave

From: Kent M Pitman
Subject: Re: DEFINE-MODIFY-MACRO usage question
Date: 
Message-ID: <sfwg0h1db1p.fsf@world.std.com>
David Bakhash <·····@alum.mit.edu> writes:

> I recently wanted similar functionality to that (basically, I wanted a
> DELETEF macro).  I wrote the one below, and wanted to compare it with
> the implementation above.
> 
> My implementation is as follows:
> 
> (defun delete* (list elt &rest args)
>   (apply #'delete elt list args))
> 
> (define-modify-macro delete*f (&rest args)
>   delete*)
> 
> (defmacro deletef (elt list &rest args)
>   `(delete*f ,list ,elt ,@args))
> 
> I wrote it like that (i.e. with the nasty delete*f) because I wanted
> to preserve the order that delete used in the new deletef, and I
> wasn't aware of another way.

FWIW, and it's mostly a personal taste issue, I use the following naming
conventions in my code:


  FOO*   Same function FOO but with a spread last argument.
         e.g., absent history, what CL calls APPLY I'd call FUNCALL*.


  XFOO   Same as FOO but with arguments swapped.  Maclisp used to have an
         XCONS operator (sometimes useful for mapping and other higher order
         functions) that took CONS arguments backwards.
  
What you've called DELETE*, I'd have called XDELETE.  Then you could make
the macro XDELETEF.

What naming conventions you use aren't as important as that you pick a set
of naming conventions to use consistently across your code so that if someone
sees FOO* out of context, they have a good guess what it means without having
to look at the definition if they know how you code.  So unless you use
FOO* to consistently mean "reverse the args" or at least "reorder the args",
then you might consider adopting a different or more consistent style.
 
> The reason I wasn't sure I'd rather use GET-SETF-EXPANSION here is
> that environment argument, which I don't feel belongs here, and I
> avoided with define-modify-macro, whereas the DROP implementation
> accepts the environment keyword argument, I'm guessing that
> DEFINE-MODIFY-MACRO bypasses that, somehow.

It does this implicitly within it.

 (XDELETEF place y)

becomes 

 (SETF place (XDELETE place y))

but with appropriate calls to the GET-SETF-EXPANSION in order to avoid
multiple evaluation of place's subforms.  THe macro definition into which 
DEFINE-MODIFY-MACRO expands should contian &ENVIRONMENT and all that 
invisibly to you (unless you expand it to check).
From: David Bakhash
Subject: Re: DEFINE-MODIFY-MACRO usage question
Date: 
Message-ID: <m3d7c5sy2i.fsf@cadet.dsl.speakeasy.net>
Kent M Pitman <······@world.std.com> writes:

> FWIW, and it's mostly a personal taste issue, I use the following naming
> conventions in my code:
> 
> 
>   FOO*   Same function FOO but with a spread last argument.
>          e.g., absent history, what CL calls APPLY I'd call FUNCALL*.

I'm pretty sure that this convention won't work for me, as I often
append `*' when I simply want to slightly change the semantics.  But
given the way list* works in CL, I think I prefer your convention to
mine, the more I think about it.  It's just that yours doesn't come up 
too often for me.

>   XFOO   Same as FOO but with arguments swapped.  Maclisp used to have an
>          XCONS operator (sometimes useful for mapping and other higher order
>          functions) that took CONS arguments backwards.

adopted.  Works for me.

> > The reason I wasn't sure I'd rather use GET-SETF-EXPANSION here is
> > that environment argument, which I don't feel belongs here, and I
> > avoided with define-modify-macro, whereas the DROP implementation
> > accepts the environment keyword argument, I'm guessing that
> > DEFINE-MODIFY-MACRO bypasses that, somehow.
> 
> It does this implicitly within it.
> 
>  (XDELETEF place y)
> 
> becomes 
> 
>  (SETF place (XDELETE place y))
> 
> but with appropriate calls to the GET-SETF-EXPANSION in order to avoid
> multiple evaluation of place's subforms.  THe macro definition into which 
> DEFINE-MODIFY-MACRO expands should contian &ENVIRONMENT and all that 
> invisibly to you (unless you expand it to check).

maybe so.  so what you're saying is that the two implementations are
the same, even with respect to the environment argument?

dave
From: Kent M Pitman
Subject: Re: DEFINE-MODIFY-MACRO usage question
Date: 
Message-ID: <sfwbsrpbb9n.fsf@world.std.com>
David Bakhash <·····@alum.mit.edu> writes:

> > > The reason I wasn't sure I'd rather use GET-SETF-EXPANSION here
> > > is that environment argument, which I don't feel belongs here,
> > > and I avoided with define-modify-macro, whereas the DROP
> > > implementation accepts the environment keyword argument, I'm
> > > guessing that DEFINE-MODIFY-MACRO bypasses that, somehow.
> > 
> > It does this implicitly within it.
> > 
> >  (XDELETEF place y)
> > 
> > becomes 
> > 
> >  (SETF place (XDELETE place y))
> > 
> > but with appropriate calls to the GET-SETF-EXPANSION in order to
> > avoid multiple evaluation of place's subforms.  THe macro
> > definition into which DEFINE-MODIFY-MACRO expands should contian
> > &ENVIRONMENT and all that invisibly to you (unless you expand it
> > to check).
> 
> maybe so.  so what you're saying is that the two implementations are
> the same, even with respect to the environment argument?

Well, I didn't look at it in detail, but probably close.  There's a
stray `:count 1' injected in your first example but not in your
second, so they can't be really identical.  Plus the expansion of
DEFINE-MODIFY-MACRO isn't specified by the spec, so verifying that it
was the same would have to be done on an
implementation-by-implementation basis.  But it looks basically the
same to me at quick glance anyway...
From: Pekka P. Pirinen
Subject: Re: DEFINE-MODIFY-MACRO usage question
Date: 
Message-ID: <ixae76agb8.fsf@harlequin.co.uk>
Kent M Pitman <······@world.std.com> writes:
> David Bakhash <·····@alum.mit.edu> writes:
> > maybe so.  so what you're saying is that the two implementations are
> > the same, even with respect to the environment argument?
> 
> Well, I didn't look at it in detail, but probably close.  There's a
> stray `:count 1' injected in your first example but not in your
> second, so they can't be really identical.

Yes, they're close, but there's a reason #:Erik wrote it like that and
named it like that.  Your DELETEF breaks the naming convention of
modify macros, by looking like one, even though the arguments are in
the opposite order; DROP is a better name.  More seriously, your
DELETEF breaks the CL convention on argument evaluation order, since
subforms of LIST will be evaluated before ELT; if you want to pass the
arguments in that order, you need to implement it the hard way, using
GET-SETF-EXPANSION.

> that environment argument, which I don't feel belongs here,

Note that &ENVIRONMENT is always transparent to the caller, see
<http://www.xanalys.com/software_tools/reference/HyperSpec/Body/glo_e.html#environment_parameter>,
and almost always The Right Thing.

Also, DROP does multiple-value places by modifying the first value and
preserving the rest; DEFINE-MODIFY-MACRO just drops the other values.
Applying a modify macro to a multiple-value place is probably bug, but
if you need to do that, implement what you need.

> (define-modify-macro delete*f (&rest args)
>   delete*)

BTW, DELETE*F has a useless lambda list, it would be better to declare
the real one: (ELT &REST KEYS) -- even though this makes no difference
to the macro expansion, you get better doc and perhaps error checking.
Also, you could just use a lambda expression here, instead of naming
a function.

You might usefully compare these to LispWorks' LW:REMOVEF
<http://www.xanalys.com/software_tools/reference/lwl41/lwref/LWRM_227.HTM#HEADING227-0>.
-- 
Pekka P. Pirinen, Adaptive Memory Management Group, Harlequin Limited
A definition tells you something about the way words are used, 
not about the way the universe is put together.
  - Simon van Dongen <sgvd_pi.net>