Package: emacs;
Reported by: "Drew Adams" <drew.adams <at> oracle.com>
Date: Thu, 30 Aug 2012 23:10:01 UTC
Severity: normal
Found in version 24.2.50
Done: Chong Yidong <cyd <at> gnu.org>
Bug is archived. No further changes may be made.
Message #58 received at 12314 <at> debbugs.gnu.org (full text, mbox):
From: "Drew Adams" <drew.adams <at> oracle.com> To: "'Eli Zaretskii'" <eliz <at> gnu.org> Cc: 12314 <at> debbugs.gnu.org, cyd <at> gnu.org Subject: RE: bug#12314: 24.2.50; `add-to-history': use `setq' with `delete' 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.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.