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

From: "Drew Adams" <[email-masked]>
Date: Sat, 8 Sep 2012 15:26:04 -0700

> > > Why is it even necessary to talk about destructive 
> > > modifications, if we are to advise to assign the result anyway?
> > 
> > Not sure I understand the question.  It is because these 
> > operations can be destructive of list structure that we advise that.
> 
> If you need to forget about the old value and assign the new one
> returned by 'delete', why does it matter that the modification was
> destructive?  That pertains to the old value that you need to toss
> anyway.

Perhaps we are miscommunicating.

That general advice about assigning the variable is only a general guideline; it
is not absolute.  You will NOT always want to assign the variable to the return
value.  It all depends on what you want/need.

The doc about these operations needs to describe what they do, and what they do
is typically destructive; that is, they typically modify list structure.

The bit about variables here is only a heads-up about a classic gotcha, nothing
more.  It is because we often have variables that are assigned/bound to the list
structure that we might be modifying that we should BE AWARE that these
operations do NOT do ANYTHING wrt variables.  

All they do is modify list structure.  We typically give them access to the list
structure via the values of variables.  But the operations have nothing to do
with the variables themselves - they are completely unaware of the existence of
any variables.

Hence, IF you want your variable, and not just some particular list structure,
to always be updated to reflect your modification, then that is a separate step
that you must perform after modification: assign the variable to the resulting
list structure that you want.

This is not so obvious to newbies, just as fiddling with pointers is not obvious
to a newbie to a language that has pointers.

A function such as `add-to-history' or `add-to-list' is something quite
different.  Those functions act on a VARIABLE, whose value is a list.  IOW, they
are aware of the existence of a certain variable - they are passed the SYMBOL as
argument, not just its value, and they make sure that the variable gets updated.

The modification functions that operate only on lists have no awareness of any
variables.  They are not passed a variable as argument.  Their job is simply to
return a list value, possibly (typically) modifying existing list structure in
the process.

> > If you have variables that point to some list structure 
> > that you modify somehow, then it is up to you to ensure that
> > the variables point to what you want them to point to after
> > such modification.
> 
> Variables that point to that list structure will point to something
> whose value is unpredictable, a.k.a. "garbage".  It is enough to say
> that the old value is garbage and shouldn't be used, IMO.

No.  It all depends.  Lisp programs that use list modification do so sometimes
for performance in calculating the new list, but more often they do so in order
to take advantage of SHARING list structure.

(This too is something not so obvious to newbies - they can get the impression
that these operations are mainly about saving cycles in calculating the return
value.)

For such programs - which are IMO the typical and the strongest (most important)
uses of list modification, what you call garbage is anything but.

Consider the example I gave before:

(setq a  '(1 2 3 4))
(setq b  (cddr a))

a => (1 2 3 4)
b => (3 4)

(delq 4 b)

a => (1 2 3)
b => (3)

The fact that modifying the list pointed to by `b' also modifies the list
pointed to by `a' is an advantage for certain kinds of programs.  Without a
separate `setq' operation, the variables point to the same cons cells they
pointed to at the outset.  And in some cases that is exactly what you want: you
want to remove the last link in the list that is shared by `a' and `b'.

List structure can be shared among multiple variables, so that changes to the
structure are seen by more than one - perhaps all.  Each variable provides a
different view of parts or all of the list structure.

> > It all depends on what you want/need.
> 
> You can never want/need the old value, because you cannot predict what
> it will be.

Not so.  If you know `a' and `b' before the operation then you know them
afterward as well.

What `a' and `b' here do NOT care about is `4' or the cons that contains `4' in
its car.  To THEM it is now garbage - it is no longer part of the lists THEY
point to.  But some other variable, `c', might well care about (point to) that
particular cons.  E.g.,

(setq a  '(1 2 3 4))
(setq b  (cddr a))
(setq c  (cdr b))

Here, `c' points to the last cons cell in `a' and `b'.  After the `delq'
operation, that cons cell is no longer part of the lists pointed to by `a' and
`b'.  But it is still pointed to by `c'.

And in such programs it can also be the case that what is garbage to `a' and `b'
now will later be important to them.  IOW, these 3 lists/views might well be
logically related and dynamically change in related ways.  

Removing the sublist `c' from `a' and `b' might be a temporary operation - that
sublist might be added back later.  And when it is added back it might no longer
contain `4' - it might then be (42 19 "hike").  You get the point.

It is probably easier to see all of this by looking at `setcar' and `setcdr'.
For `delq' we do not necessarily want/need to expose exactly how the
implementation works, other than to say what it does in general and point out
that it might NOT modify any existing list structure in some cases.  But for
`setcar' and `setcdr' the behavior is transparent and simple.  They always
modify list structure, and in simple ways.

Think of variables whose values are cons cells as pointers.  List modification
can move such pointers around.  In the above case, the pointer from the cdr of
the first cons of `b' to its second cons is changed to point to nil.  That's
all.  And `b' is a sublist of `a', so now `a's value reflects the structure
change also.

That can be a very handy thing.  Certain kinds of programs take advantage of
this sharing.  Others - most - do not.