bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'


From: Drew Adams
Subject: bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
Date: Sat, 8 Sep 2012 08:48:53 -0700

> That for a list, assigning the result is not necessary.  At least
> that's my interpretation of what the manual says.

No, that is incorrect.  This is an old Lisp gotcha.  It is one reason people
often advise Lisp newbies not to start out by using destructive operations.
They can be quite confusing, and you can run into trouble far from where a
problem/bug is introduced.

> > Keep reading the same section of the manual (section for `delete'):
> > 
> >   ;; If you want to change `l' reliably,
> >   ;; write `(setq l (delete '(2) l))'.
> 
> My interpretation of "reliably" here is "without assuming that l is a
> list".  Is that a wrong interpretation?

Yes, it is wrong.

> > There is more explanation higher up in the same node, under `delq':
> 
> 'delq' is not identical to 'delete', so assumptions that somethiong
> described there is pertinent to 'delete' are unsafe.  And how should
> the reader know that she needs to read something under 'delq' to fully
> understand what 'delete' does, anyway?

The doc for `delete' sends you to the doc for `delq', where there is a good
step-by-step illustration.  The only difference between `delq' and `delete' is
comparison by `eq' vs by `equal'.

This is in fact a general thing for Lisp functions that are destructive of list
structure.

The manual describes it for `delq':

 When `delq' deletes elements from the front of the list, it
 does so simply by advancing down the list and returning a
 sublist that starts after those elements:

     (delq 'a '(a b c)) == (cdr '(a b c))

The point is not to confuse the _side effect_ of an operation (so-called
"function") such as `delete' with its _return value_.

The list targeted by the function might or might not be modified.  The return
value has the correct contents in all cases, and that is why you should
generally set your variable to the return value, if you want that variable to
reflect the result of the operation.

The list structure is one thing.  Your variable pointing to some list structure
is another thing.  If you want the variable to reflect the changed structure
(list contents) in all cases, then set the variable value to the function's
return value.

In short, to reflect the _result_ of the operation, you need to set the variable
to the returned result.  Otherwise, it will not necessarily point to a list that
has the correct contents.

> I'm not sure who is missing what.  All I'm saying is that the manual
> seems to suggest that an explicit assignment is unnecessary, and yet
> Chong did exactly that.  If just "(delete 'foo bar)", with 'bar' a
> list, is sometimes not enough, the manual should say when.  And if it
> is enough, why should we make the change in add-to-history?

It is not enough, if you need the variable to reflect the updated list contents.
It's about using the return value of the function vs depending on the "function"
only for its side effect (i.e., not caring about what the variable points to
after the operation).

If we cared only about a particular list structure and not some variable that
might point to it, then we might not bother to update the variable by setting it
to the returned value.

> IOW, it sounds like some kind of black magic is going on under the
> hood, but the manual is too shy to talk about it.  It shouldn't; doing
> so could easily spread confusion.  I'm not sure the code in question
> was written as it was due to that confusion.

It's not black magic, but it is about list structure and Lisp not being a
(purely) functional language.

Perhaps the node `Modifying Lists' should go into a little more detail about
this; dunno.  `delq' or `delete' is a great way to illustrate it, and we
currently do that (for `delq').  Perhaps we should be more explicit about other
list-modifying (i.e. destructive) operations having the same behavior, and
generally advise setting any variable you care about to the returned value of
the function.






reply via email to

[Prev in Thread] Current Thread [Next in Thread]