* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
@ 2012-08-30 23:08 Drew Adams
2012-09-08 14:32 ` Chong Yidong
2012-09-09 8:25 ` Dmitry Gutov
0 siblings, 2 replies; 37+ messages in thread
From: Drew Adams @ 2012-08-30 23:08 UTC (permalink / raw
To: 12314
This line in `add-to-history':
(if history-delete-duplicates (delete newelt history))
should be this:
(if history-delete-duplicates (setq history (delete newelt history)))
(Or for more clarity, use `when' instead of `if'.)
I'm not 100% sure this is a problem, but it seems to be in a case I saw.
And there seems to be no reason not to set `history' to the `delete'
result here.
In GNU Emacs 24.2.50.1 (i386-mingw-nt5.1.2600)
of 2012-08-26 on MARVIN
Bzr revision: 109788 dmantipov@yandex.ru-20120827041533-3cy7pdjdqz14o90c
Windowing system distributor `Microsoft Corp.', version 5.1.2600
Configured using:
`configure --with-gcc (4.6) --no-opt --enable-checking --cflags
-ID:/devel/emacs/libs/libXpm-3.5.8/include
-ID:/devel/emacs/libs/libXpm-3.5.8/src
-ID:/devel/emacs/libs/libpng-dev_1.4.3-1/include
-ID:/devel/emacs/libs/zlib-dev_1.2.5-2/include
-ID:/devel/emacs/libs/giflib-4.1.4-1/include
-ID:/devel/emacs/libs/jpeg-6b-4/include
-ID:/devel/emacs/libs/tiff-3.8.2-1/include
-ID:/devel/emacs/libs/gnutls-3.0.9/include
-ID:/devel/emacs/libs/libiconv-1.13.1-1-dev/include
-ID:/devel/emacs/libs/libxml2-2.7.8/include/libxml2'
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-08-30 23:08 bug#12314: 24.2.50; `add-to-history': use `setq' with `delete' Drew Adams
@ 2012-09-08 14:32 ` Chong Yidong
2012-09-08 14:43 ` Eli Zaretskii
2012-09-09 8:25 ` Dmitry Gutov
1 sibling, 1 reply; 37+ messages in thread
From: Chong Yidong @ 2012-09-08 14:32 UTC (permalink / raw
To: Drew Adams; +Cc: 12314
"Drew Adams" <drew.adams@oracle.com> writes:
> This line in `add-to-history':
>
> (if history-delete-duplicates (delete newelt history))
>
> should be this:
>
> (if history-delete-duplicates (setq history (delete newelt history)))
Fixed, thanks.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 14:32 ` Chong Yidong
@ 2012-09-08 14:43 ` Eli Zaretskii
2012-09-08 14:57 ` Drew Adams
0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-08 14:43 UTC (permalink / raw
To: Chong Yidong; +Cc: 12314
> From: Chong Yidong <cyd@gnu.org>
> Date: Sat, 08 Sep 2012 22:32:13 +0800
> Cc: 12314@debbugs.gnu.org
>
> "Drew Adams" <drew.adams@oracle.com> writes:
>
> > This line in `add-to-history':
> >
> > (if history-delete-duplicates (delete newelt history))
> >
> > should be this:
> >
> > (if history-delete-duplicates (setq history (delete newelt history)))
>
> Fixed, thanks.
Does this mean the ELisp manual is in error? It says:
-- Function: delete object sequence
If `sequence' is a list, this function destructively removes all
elements `equal' to OBJECT from SEQUENCE.
...
If `sequence' is a vector or string, `delete' returns a copy of
`sequence' with all elements `equal' to `object' removed.
'history' is a list, isn't it?
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 14:43 ` Eli Zaretskii
@ 2012-09-08 14:57 ` Drew Adams
2012-09-08 15:20 ` Eli Zaretskii
0 siblings, 1 reply; 37+ messages in thread
From: Drew Adams @ 2012-09-08 14:57 UTC (permalink / raw
To: 'Eli Zaretskii', 'Chong Yidong'; +Cc: 12314
> Does this mean the ELisp manual is in error? It says:
>
> -- Function: delete object sequence
> If `sequence' is a list, this function destructively removes all
> elements `equal' to OBJECT from SEQUENCE.
> ...
> If `sequence' is a vector or string, `delete' returns a copy of
> `sequence' with all elements `equal' to `object' removed.
>
> 'history' is a list, isn't it?
Yes, it is a list. What is your point/question?
Keep reading the same section of the manual (section for `delete'):
;; If you want to change `l' reliably,
;; write `(setq l (delete '(2) l))'.
There is more explanation higher up in the same node, under `delq':
Don't assume that a variable
which formerly held the argument LIST now has fewer elements,
or that it still holds the original list! Instead, save the
result of `delq' and use that. Most often we store the result
back into the variable that held the original list:
(setq flowers (delq 'rose flowers))
I would imagine that you already know this, so I'm likely missing something in
your question. But if you don't already know this, or if you knew it but forgot
it, there's no harm/shame in that. Does this help, or were you referring to
something else?
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 14:57 ` Drew Adams
@ 2012-09-08 15:20 ` Eli Zaretskii
2012-09-08 15:48 ` Drew Adams
0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-08 15:20 UTC (permalink / raw
To: Drew Adams; +Cc: 12314, cyd
> From: "Drew Adams" <drew.adams@oracle.com>
> Cc: <12314@debbugs.gnu.org>
> Date: Sat, 8 Sep 2012 07:57:12 -0700
>
> > Does this mean the ELisp manual is in error? It says:
> >
> > -- Function: delete object sequence
> > If `sequence' is a list, this function destructively removes all
> > elements `equal' to OBJECT from SEQUENCE.
> > ...
> > If `sequence' is a vector or string, `delete' returns a copy of
> > `sequence' with all elements `equal' to `object' removed.
> >
> > 'history' is a list, isn't it?
>
> Yes, it is a list. What is your point/question?
That for a list, assigning the result is not necessary. At least
that's my interpretation of what the manual says.
> 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?
> 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?
> I would imagine that you already know this, so I'm likely missing something in
> your question.
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?
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.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 15:20 ` Eli Zaretskii
@ 2012-09-08 15:48 ` Drew Adams
2012-09-08 16:05 ` Eli Zaretskii
0 siblings, 1 reply; 37+ messages in thread
From: Drew Adams @ 2012-09-08 15:48 UTC (permalink / raw
To: 'Eli Zaretskii'; +Cc: 12314, cyd
> 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.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 15:48 ` Drew Adams
@ 2012-09-08 16:05 ` Eli Zaretskii
2012-09-08 16:19 ` Andreas Schwab
2012-09-08 16:25 ` Drew Adams
0 siblings, 2 replies; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-08 16:05 UTC (permalink / raw
To: Drew Adams; +Cc: 12314, cyd
> From: "Drew Adams" <drew.adams@oracle.com>
> Cc: <cyd@gnu.org>, <12314@debbugs.gnu.org>
> Date: Sat, 8 Sep 2012 08:48:53 -0700
>
> > 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.
Then the manual should be corrected to state that much more explicitly
than it does now. Perhaps it shouldn't even talk about destructive
removal, as that will surely spread confusion. For me "destructive"
means "in-place", and no amount of describing how 'delete' works
internally will ever be able to countermand that. Besides, if all I
need is a quick reminder about the semantics, I'm unlikely to read all
the verbiage, let alone go up to read more under 'delq'. So the most
important facts should be right there at the beginning, not hidden
away under "note that" etc.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:05 ` Eli Zaretskii
@ 2012-09-08 16:19 ` Andreas Schwab
2012-09-08 16:33 ` Eli Zaretskii
2012-09-08 16:35 ` Drew Adams
2012-09-08 16:25 ` Drew Adams
1 sibling, 2 replies; 37+ messages in thread
From: Andreas Schwab @ 2012-09-08 16:19 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314, cyd
Eli Zaretskii <eliz@gnu.org> writes:
> Then the manual should be corrected to state that much more explicitly
> than it does now. Perhaps it shouldn't even talk about destructive
> removal, as that will surely spread confusion. For me "destructive"
> means "in-place", and no amount of describing how 'delete' works
> internally will ever be able to countermand that.
Even if the element is not the first one, you always have to think about
other references that may exist to the cons that is removed.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:05 ` Eli Zaretskii
2012-09-08 16:19 ` Andreas Schwab
@ 2012-09-08 16:25 ` Drew Adams
2012-09-08 16:32 ` Eli Zaretskii
1 sibling, 1 reply; 37+ messages in thread
From: Drew Adams @ 2012-09-08 16:25 UTC (permalink / raw
To: 'Eli Zaretskii'; +Cc: 12314, cyd
> > It is not enough, if you need the variable to reflect the
> > updated list contents.
>
> Then the manual should be corrected to state that much more explicitly
> than it does now. Perhaps it shouldn't even talk about destructive
> removal, as that will surely spread confusion. For me "destructive"
> means "in-place", and no amount of describing how 'delete' works
> internally will ever be able to countermand that. Besides, if all I
> need is a quick reminder about the semantics, I'm unlikely to read all
> the verbiage, let alone go up to read more under 'delq'. So the most
> important facts should be right there at the beginning, not hidden
> away under "note that" etc.
Go for it. I suggest mentioning something like this in node `Modifying Lists'
(and then cross-ref'ing that node from other nodes about functions that are
destructive of list structure):
Typically, you want a variable whose value is a list to reflect the result of
any destructive operation on that list. To achieve that, set the variable value
to the value returned by that operation.
The reason for this is that operations that modify list structure do not also
update any variables that might point to such structure. They are concerned
only with changing list structure.
Then give the `delq' example as an illustration of this. Point out why the
variable's value no longer reflects the updated list content. (Perhaps even use
a cons-cell diagram to illustrate.)
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:
(setq sample-list '(a b c (4)))
=> (a b c (4))
(delq 'a sample-list) => (b c (4))
sample-list => (a b c (4))
Mention explicitly that the same thing is involved with *ALL* list-modification
operations. The only things guaranteed by such operations are (a) the
modification of the list structure takes place as advertised, and (b) the return
value reflects the modified list structure correctly.
So if you want a variable to reflect the list correctly as modified then set its
value to the return value of the modification function.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:25 ` Drew Adams
@ 2012-09-08 16:32 ` Eli Zaretskii
2012-09-08 16:42 ` Drew Adams
0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-08 16:32 UTC (permalink / raw
To: Drew Adams; +Cc: 12314, cyd
> From: "Drew Adams" <drew.adams@oracle.com>
> Cc: <cyd@gnu.org>, <12314@debbugs.gnu.org>
> Date: Sat, 8 Sep 2012 09:25:08 -0700
>
> Go for it. I suggest mentioning something like this in node `Modifying Lists'
> (and then cross-ref'ing that node from other nodes about functions that are
> destructive of list structure):
Why is it even necessary to talk about destructive modifications, if
we are to advise to assign the result anyway?
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:19 ` Andreas Schwab
@ 2012-09-08 16:33 ` Eli Zaretskii
2012-09-08 16:50 ` Lars Ingebrigtsen
` (2 more replies)
2012-09-08 16:35 ` Drew Adams
1 sibling, 3 replies; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-08 16:33 UTC (permalink / raw
To: Andreas Schwab; +Cc: 12314, cyd
> From: Andreas Schwab <schwab@linux-m68k.org>
> Cc: Drew Adams <drew.adams@oracle.com>, 12314@debbugs.gnu.org, cyd@gnu.org
> Date: Sat, 08 Sep 2012 18:19:58 +0200
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
> > Then the manual should be corrected to state that much more explicitly
> > than it does now. Perhaps it shouldn't even talk about destructive
> > removal, as that will surely spread confusion. For me "destructive"
> > means "in-place", and no amount of describing how 'delete' works
> > internally will ever be able to countermand that.
>
> Even if the element is not the first one, you always have to think about
> other references that may exist to the cons that is removed.
Sorry, I'm not sure how this is related. Please elaborate.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:19 ` Andreas Schwab
2012-09-08 16:33 ` Eli Zaretskii
@ 2012-09-08 16:35 ` Drew Adams
1 sibling, 0 replies; 37+ messages in thread
From: Drew Adams @ 2012-09-08 16:35 UTC (permalink / raw
To: 'Andreas Schwab', 'Eli Zaretskii'; +Cc: 12314, cyd
> > Then the manual should be corrected to state that much more
> > explicitly than it does now. Perhaps it shouldn't even talk
> > about destructive removal, as that will surely spread
> > confusion. For me "destructive" means "in-place", and no
> > amount of describing how 'delete' works internally will ever
> > be able to countermand that.
>
> Even if the element is not the first one, you always have to
> think about other references that may exist to the cons that
> is removed.
Exactly. That too merits an explicit mention. That is an even more insidious
source of hard-to-find bugs.
There is no harm in driving this point home, even at the risk of some
repetition. Destructive operations should not be used without extra care. It
is a gotcha that newbies sometimes learn the hard way.
In particular, thinking that such operations are only about performance, and
understanding that they can be more performant, newbies sometimes start using
them right off the bat (premature optimization). And because the gotchas only
surface in some situations, they don't necessarily notice problems right away.
IIRC, the Common Lisp manual was pretty good at essentially warning readers not
to use destructive operations unless they really understand them well. I don't
recall just what was said, though.
A simple guideline to set your variable to the list returned by such an
operation will go a long way, I think. But we should of course explain why
also.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:32 ` Eli Zaretskii
@ 2012-09-08 16:42 ` Drew Adams
2012-09-08 21:21 ` Eli Zaretskii
0 siblings, 1 reply; 37+ messages in thread
From: Drew Adams @ 2012-09-08 16:42 UTC (permalink / raw
To: 'Eli Zaretskii'; +Cc: 12314, cyd
> 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.
These operations are not concerned with any variables, period - they act only on
list structure.
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.
It all depends on what you want/need.
(This is a bit like using pointers. A variable points to a particular cons
cell. Modifying one or more cons cells in a chain might or might not change
that particular cons cell or cells that its cdr points to. The variable
continues to point to the same cons cell, but that cell might not still reflect
the "list" that you expect it to reflect.)
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:33 ` Eli Zaretskii
@ 2012-09-08 16:50 ` Lars Ingebrigtsen
2012-09-08 16:54 ` Drew Adams
2012-09-08 17:06 ` Andreas Schwab
2 siblings, 0 replies; 37+ messages in thread
From: Lars Ingebrigtsen @ 2012-09-08 16:50 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314, cyd, Andreas Schwab
Eli Zaretskii <eliz@gnu.org> writes:
> Sorry, I'm not sure how this is related. Please elaborate.
`delete' may modify the list, so other references into the list may get
surprising results after you've modified it.
The current doc string is kinda obscure, though. It stars with
---
Delete by side effect any occurrences of ELT as a member of SEQ.
---
which is like "err".
Perhaps something like
Delete any occurrences of ELT from SEQ. This operation may
destructively modify SEQ. See `remove' for a non-destructive version.
would be more readable.
--
(domestic pets only, the antidote for overdose, milk.)
http://lars.ingebrigtsen.no * Lars Magne Ingebrigtsen
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:33 ` Eli Zaretskii
2012-09-08 16:50 ` Lars Ingebrigtsen
@ 2012-09-08 16:54 ` Drew Adams
2012-09-08 17:06 ` Andreas Schwab
2 siblings, 0 replies; 37+ messages in thread
From: Drew Adams @ 2012-09-08 16:54 UTC (permalink / raw
To: 'Eli Zaretskii', 'Andreas Schwab'; +Cc: 12314, cyd
> > Even if the element is not the first one, you always have
> > to think about other references that may exist to the
> > cons that is removed.
>
> Sorry, I'm not sure how this is related. Please elaborate.
(Think pointers.) A variable stays pointed to the same cons cell - these
operations do not change that. But they can change the relations among cons
cells: which of them point to which others.
(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 value of variable `a' was changed by changing the value of `b', because `b'
points to a cons cell that is used in the list structure pointed to by `a'.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:33 ` Eli Zaretskii
2012-09-08 16:50 ` Lars Ingebrigtsen
2012-09-08 16:54 ` Drew Adams
@ 2012-09-08 17:06 ` Andreas Schwab
2 siblings, 0 replies; 37+ messages in thread
From: Andreas Schwab @ 2012-09-08 17:06 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314, cyd
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Andreas Schwab <schwab@linux-m68k.org>
>> Cc: Drew Adams <drew.adams@oracle.com>, 12314@debbugs.gnu.org, cyd@gnu.org
>> Date: Sat, 08 Sep 2012 18:19:58 +0200
>>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>> > Then the manual should be corrected to state that much more explicitly
>> > than it does now. Perhaps it shouldn't even talk about destructive
>> > removal, as that will surely spread confusion. For me "destructive"
>> > means "in-place", and no amount of describing how 'delete' works
>> > internally will ever be able to countermand that.
>>
>> Even if the element is not the first one, you always have to think about
>> other references that may exist to the cons that is removed.
>
> Sorry, I'm not sure how this is related. Please elaborate.
It's just a special case of this general behaviour.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 16:42 ` Drew Adams
@ 2012-09-08 21:21 ` Eli Zaretskii
2012-09-08 22:26 ` Drew Adams
2012-09-08 23:11 ` Stefan Monnier
0 siblings, 2 replies; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-08 21:21 UTC (permalink / raw
To: Drew Adams; +Cc: 12314, cyd
> From: "Drew Adams" <drew.adams@oracle.com>
> Cc: <cyd@gnu.org>, <12314@debbugs.gnu.org>
> Date: Sat, 8 Sep 2012 09:42:59 -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.
> 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.
> It all depends on what you want/need.
You can never want/need the old value, because you cannot predict what
it will be.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 21:21 ` Eli Zaretskii
@ 2012-09-08 22:26 ` Drew Adams
2012-09-09 3:00 ` Eli Zaretskii
2012-09-10 11:54 ` Wolfgang Jenkner
2012-09-08 23:11 ` Stefan Monnier
1 sibling, 2 replies; 37+ messages in thread
From: Drew Adams @ 2012-09-08 22:26 UTC (permalink / raw
To: 'Eli Zaretskii'; +Cc: 12314, cyd
> > > 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.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 21:21 ` Eli Zaretskii
2012-09-08 22:26 ` Drew Adams
@ 2012-09-08 23:11 ` Stefan Monnier
2012-09-09 2:51 ` Eli Zaretskii
1 sibling, 1 reply; 37+ messages in thread
From: Stefan Monnier @ 2012-09-08 23:11 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314, cyd
>> > 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?
Because it avoids memory allocation. I.e. 99% of the uses of
delete/delq/nconc are simple optimizations.
Stefan
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 23:11 ` Stefan Monnier
@ 2012-09-09 2:51 ` Eli Zaretskii
2012-09-09 14:44 ` Stefan Monnier
0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-09 2:51 UTC (permalink / raw
To: Stefan Monnier; +Cc: 12314, cyd
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Drew Adams <drew.adams@oracle.com>, 12314@debbugs.gnu.org, cyd@gnu.org
> Date: Sat, 08 Sep 2012 19:11:50 -0400
>
> >> > 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?
>
> Because it avoids memory allocation. I.e. 99% of the uses of
> delete/delq/nconc are simple optimizations.
I meant "why does it matter FOR THE USER that the modification was
destructive?" Users don't care about optimizations, they only care
about performance.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 22:26 ` Drew Adams
@ 2012-09-09 3:00 ` Eli Zaretskii
2012-09-09 6:29 ` Drew Adams
2012-09-09 7:53 ` Chong Yidong
2012-09-10 11:54 ` Wolfgang Jenkner
1 sibling, 2 replies; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-09 3:00 UTC (permalink / raw
To: Drew Adams; +Cc: 12314, cyd
> From: "Drew Adams" <drew.adams@oracle.com>
> Cc: <cyd@gnu.org>, <12314@debbugs.gnu.org>
> 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.
Please describe the situations with using 'delete' when the old value
will be wanted. (Please try to do that succinctly, because I get lost
in your longish deliberations.)
> 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.
Being aware doesn't solve problems. To write reliable code, one needs
to always do certain things. My understanding is that one must always
assign the new value, because the old one is unpredictable in general.
> > > 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.)
But the manual should cater first and foremost to newbies. The rest
will get the point when they read the detailed description of how the
list is modified.
> (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'.
I fail to see the utility of this. Building code that relies on
internal implementation details is never a good idea. But that's me;
please don't bother to argue.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 3:00 ` Eli Zaretskii
@ 2012-09-09 6:29 ` Drew Adams
2012-09-09 7:53 ` Chong Yidong
1 sibling, 0 replies; 37+ messages in thread
From: Drew Adams @ 2012-09-09 6:29 UTC (permalink / raw
To: 'Eli Zaretskii'; +Cc: 12314, cyd
> > 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.
>
> I fail to see the utility of this. Building code that relies on
> internal implementation details is never a good idea. But that's me;
> please don't bother to argue.
Intentional list modification is not an implementation detail. That is, it
concerns the implementation of your program, of course, but not the
implementation of Lisp itself. You have to know what a given Lisp operation
does (side effects) and what it returns, but not how it is implemented.
My description of this area apparently did not help you.
Perhaps someone else can do better.
You might start here: (elisp) `Modifying Lists'.
You might search there for "share|sharing".
You might also google for, say, "lisp sharing list structure modification".
Looking at some of the hits, I think several should be helpful.
Here's one that might be another place to start:
http://en.wikipedia.org/wiki/Lisp_(programming_language)#Shared_structure
Perhaps you can imagine a complex program with a humongous graph structure
(already you see some sharing), which is dynamically modified. Imagine
different views (e.g., variables) into various parts of that structure. This
kind of Lisp program is not uncommon in some applications. (The same could be
done using Java or C or whatever, but Lisp is good for doing things with lists.)
Lisp is not a purely functional language. You need not like that, and you are
not forced to use `setf' etc. when programming in Lisp. But such operations are
a part of Lisp, and they are used by some Lisp programs. They are not a
mistake, but it is possible to make mistakes when using them.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 3:00 ` Eli Zaretskii
2012-09-09 6:29 ` Drew Adams
@ 2012-09-09 7:53 ` Chong Yidong
2012-09-09 17:25 ` Eli Zaretskii
1 sibling, 1 reply; 37+ messages in thread
From: Chong Yidong @ 2012-09-09 7:53 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314
Eli Zaretskii <eliz@gnu.org> writes:
> But the manual should cater first and foremost to newbies. The rest
> will get the point when they read the detailed description of how the
> list is modified.
I modified the manual to hopefully make the situation clearer. In
particular, the descriptions of delq and delete explicitly say that you
typically ought to use the return value.
The docstrings are harder, since they should be succinct. Here is what
I suggest; WDYT?
(delq ELT LIST)
Delete by side effect occurrences of ELT as a member of LIST.
Comparison is done with `eq'. Return the resulting list.
More precisely, this function skips any occurrences of ELT at the
front of LIST, then removes occurrences of ELT from the remaining
sublist by modifying the list structure, then returns the resulting
sublist.
Therefore, write `(setq foo (delq element foo))' to be sure of
changing the value of `foo'.
(delete ELT SEQ)
Delete occurrence of ELT as a member of SEQ.
SEQ must be a sequence (i.e. a list, a vector, or a string).
Comparison is done with `equal'. Return the resulting sequence.
If SEQ is a list, this behaves like `delq', except that it compares
with `equal' instead of `eq'. In particular, it may remove elements
by altering the list structure.
If SEQ is not a list, deletion is not a side effect; this function
creates and returns a new sequence.
Therefore, write `(setq foo (delete element foo))'
to be sure of changing the value of `foo'.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-08-30 23:08 bug#12314: 24.2.50; `add-to-history': use `setq' with `delete' Drew Adams
2012-09-08 14:32 ` Chong Yidong
@ 2012-09-09 8:25 ` Dmitry Gutov
1 sibling, 0 replies; 37+ messages in thread
From: Dmitry Gutov @ 2012-09-09 8:25 UTC (permalink / raw
To: cyd; +Cc: 12314
Chong Yidong <cyd@gnu.org> writes:
> Eli Zaretskii <eliz@gnu.org> writes:
>
>> But the manual should cater first and foremost to newbies. The rest
>> will get the point when they read the detailed description of how the
>> list is modified.
>
> I modified the manual to hopefully make the situation clearer. In
> particular, the descriptions of delq and delete explicitly say that you
> typically ought to use the return value.
>
> The docstrings are harder, since they should be succinct. Here is what
> I suggest; WDYT?
>
>
> (delq ELT LIST)
>
> ...
>
> Therefore, write `(setq foo (delq element foo))' to be sure of
> changing the value of `foo'.
I think the last sentence could be better: (a) the value of foo won't
necessarily change, even if we do (setq ...), (b) our goal is for foo to
have the correct value, some not changed one. How about this?
Therefore, write `(setq foo (delq element foo))' to make sure that
`foo' points to the result.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 2:51 ` Eli Zaretskii
@ 2012-09-09 14:44 ` Stefan Monnier
2012-09-09 17:14 ` Eli Zaretskii
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Monnier @ 2012-09-09 14:44 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314, cyd
>> Because it avoids memory allocation. I.e. 99% of the uses of
>> delete/delq/nconc are simple optimizations.
> I meant "why does it matter FOR THE USER that the modification was
> destructive?" Users don't care about optimizations, they only care
> about performance.
Because this optimization improves performance,
Stefan
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 14:44 ` Stefan Monnier
@ 2012-09-09 17:14 ` Eli Zaretskii
2012-09-09 17:35 ` Drew Adams
2012-09-09 21:37 ` Stefan Monnier
0 siblings, 2 replies; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-09 17:14 UTC (permalink / raw
To: Stefan Monnier; +Cc: 12314, cyd
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: drew.adams@oracle.com, 12314@debbugs.gnu.org, cyd@gnu.org
> Date: Sun, 09 Sep 2012 10:44:01 -0400
>
> >> Because it avoids memory allocation. I.e. 99% of the uses of
> >> delete/delq/nconc are simple optimizations.
> > I meant "why does it matter FOR THE USER that the modification was
> > destructive?" Users don't care about optimizations, they only care
> > about performance.
>
> Because this optimization improves performance,
But this optimization was already done. We don't tell users in the
manuals about each and every optimization we do to improve
performance, do we?
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 7:53 ` Chong Yidong
@ 2012-09-09 17:25 ` Eli Zaretskii
0 siblings, 0 replies; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-09 17:25 UTC (permalink / raw
To: Chong Yidong; +Cc: 12314
> From: Chong Yidong <cyd@gnu.org>
> Cc: Drew Adams <drew.adams@oracle.com>, 12314@debbugs.gnu.org
> Date: Sun, 09 Sep 2012 15:53:34 +0800
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
> > But the manual should cater first and foremost to newbies. The rest
> > will get the point when they read the detailed description of how the
> > list is modified.
>
> I modified the manual to hopefully make the situation clearer. In
> particular, the descriptions of delq and delete explicitly say that you
> typically ought to use the return value.
Thanks, the text is much better now. I still think the "destructive
modification" part should be retired to later in the description,
perhaps as notes, because it invokes mental models that get in the way
of interpreting the text correctly. But I won't fight over it.
> The docstrings are harder, since they should be succinct. Here is what
> I suggest; WDYT?
>
>
> (delq ELT LIST)
>
> Delete by side effect occurrences of ELT as a member of LIST.
> Comparison is done with `eq'. Return the resulting list.
>
> More precisely, this function skips any occurrences of ELT at the
> front of LIST, then removes occurrences of ELT from the remaining
> sublist by modifying the list structure, then returns the resulting
> sublist.
>
> Therefore, write `(setq foo (delq element foo))' to be sure of
> changing the value of `foo'.
I would remove the "by side effect" part, as it doesn't really add
anything of importance, and OTOH runs a real risk of confusing the
reader. Otherwise, I think this is fine. Thanks.
> (delete ELT SEQ)
>
> Delete occurrence of ELT as a member of SEQ.
> SEQ must be a sequence (i.e. a list, a vector, or a string).
> Comparison is done with `equal'. Return the resulting sequence.
>
> If SEQ is a list, this behaves like `delq', except that it compares
> with `equal' instead of `eq'. In particular, it may remove elements
> by altering the list structure.
>
> If SEQ is not a list, deletion is not a side effect; this function
> creates and returns a new sequence.
>
> Therefore, write `(setq foo (delete element foo))'
> to be sure of changing the value of `foo'.
This is also OK, except that I'd prefer an explicit description to a
reference to 'delq' in the second paragraph. The corresponding text
in the doc string of 'delq' is short enough, so there are no real
savings in the reference, while the disadvantage of having to consult
another doc string is real.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 17:14 ` Eli Zaretskii
@ 2012-09-09 17:35 ` Drew Adams
2012-09-09 18:20 ` Eli Zaretskii
2012-09-09 21:37 ` Stefan Monnier
1 sibling, 1 reply; 37+ messages in thread
From: Drew Adams @ 2012-09-09 17:35 UTC (permalink / raw
To: 'Eli Zaretskii', 'Stefan Monnier'; +Cc: 12314, cyd
> > >> Because it avoids memory allocation. I.e. 99% of the uses of
> > >> delete/delq/nconc are simple optimizations.
> > >
> > > I meant "why does it matter FOR THE USER that the modification was
> > > destructive?" Users don't care about optimizations, they
> > > only care about performance.
> >
> > Because this optimization improves performance,
>
> But this optimization was already done.
??
> We don't tell users in the manuals about each and every
> optimization we do to improve performance, do we?
Eli, at the risk of butting in, I respectfully suggest that you might not be
reading about this topic well enough or perhaps not thinking enough about it.
The replies to you are now repetitive because there is not much more that can be
said in response.
Stefan is making the point that when programmers use `delete' or `delq' or
`nconc' they often do so to improve the performance of their code. Which is
true.
We document what these functions do, including the fact that because of what
they do they can often improve performance. And we mention caveats that users
of such functions need to be aware of.
This is not about any optimization that "we" do in implementing Emacs, i.e.,
something that Emacs does in its implementation, under the covers.
This is about an intentional optimization that some Lisp programmers sometimes
use in their own code. You can use destructive operations like `delete' to
improve performance, but if you do so then you should be aware of some possible
pitfalls. That's all.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 17:35 ` Drew Adams
@ 2012-09-09 18:20 ` Eli Zaretskii
2012-09-09 19:46 ` Drew Adams
0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-09 18:20 UTC (permalink / raw
To: Drew Adams; +Cc: 12314, cyd
> From: "Drew Adams" <drew.adams@oracle.com>
> Cc: <12314@debbugs.gnu.org>, <cyd@gnu.org>
> Date: Sun, 9 Sep 2012 10:35:21 -0700
>
> Eli, at the risk of butting in, I respectfully suggest that you might not be
> reading about this topic well enough or perhaps not thinking enough about it.
How is this remark helpful?
> Stefan is making the point that when programmers use `delete' or `delq' or
> `nconc' they often do so to improve the performance of their code. Which is
> true.
This is an entirely different issue. "Destructive modification" does
not imply the optimization you (and evidently Stefan) are alluding to,
at least not universally so, nor a possibility to piggy-back that to
optimize application code. It just means that the original object is
modified (a.k.a. "destroyed") in the process.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 18:20 ` Eli Zaretskii
@ 2012-09-09 19:46 ` Drew Adams
0 siblings, 0 replies; 37+ messages in thread
From: Drew Adams @ 2012-09-09 19:46 UTC (permalink / raw
To: 'Eli Zaretskii'; +Cc: 12314, cyd
> > Eli, at the risk of butting in, I respectfully suggest that
> > you might not be reading about this topic well enough or
> > perhaps not thinking enough about it.
>
> How is this remark helpful?
I am sincerely _trying_ to help you. I've tried to explain and give examples.
I've pointed you to other explanations on line and elsewhere in the Elisp
manual. And I've suggested that you take a bit more time to study and think
about what you've read. And I would add, perhaps experiment.
If my attempts to help do not help you or you do not appreciate them, sorry.
This is really not that big a deal. Ask around. This is a common question and
lots of people have explained it in various ways. Take your pick.
> > Stefan is making the point that when programmers use
> > `delete' or `delq' or `nconc' they often do so to improve
> > the performance of their code. Which is true.
>
> This is an entirely different issue. "Destructive modification" does
> not imply the optimization you (and evidently Stefan) are alluding to,
> at least not universally so, nor a possibility to piggy-back that to
> optimize application code. It just means that the original object is
> modified (a.k.a. "destroyed") in the process.
To quote a famous person (you), I give up. I sincerely hope someone else helps
you find what you're looking for. If not, maybe you will reread the thread or
the manual at a later date and you will find it yourself. Sometimes that's all
it takes for things to become clear.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 17:14 ` Eli Zaretskii
2012-09-09 17:35 ` Drew Adams
@ 2012-09-09 21:37 ` Stefan Monnier
2012-09-10 4:37 ` Eli Zaretskii
1 sibling, 1 reply; 37+ messages in thread
From: Stefan Monnier @ 2012-09-09 21:37 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314, cyd
>> > I meant "why does it matter FOR THE USER that the modification was
>> > destructive?" Users don't care about optimizations, they only care
>> > about performance.
>> Because this optimization improves performance,
> But this optimization was already done. We don't tell users in the
> manuals about each and every optimization we do to improve
> performance, do we?
I don't understand the question: the user of delete/delq/nconc (the one
reading their docstring or their texinfo doc) is the person
reading/writing the code, and the optimization is the act of choosing
delete over remove or delq over remq or nconc over append, which is
exactly what the reader will want to know, I think.
Stefan
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-09 21:37 ` Stefan Monnier
@ 2012-09-10 4:37 ` Eli Zaretskii
2012-09-10 12:59 ` Stefan Monnier
0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-10 4:37 UTC (permalink / raw
To: Stefan Monnier; +Cc: 12314, cyd
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: drew.adams@oracle.com, 12314@debbugs.gnu.org, cyd@gnu.org
> Date: Sun, 09 Sep 2012 17:37:53 -0400
>
> >> > I meant "why does it matter FOR THE USER that the modification was
> >> > destructive?" Users don't care about optimizations, they only care
> >> > about performance.
> >> Because this optimization improves performance,
> > But this optimization was already done. We don't tell users in the
> > manuals about each and every optimization we do to improve
> > performance, do we?
>
> I don't understand the question: the user of delete/delq/nconc (the one
> reading their docstring or their texinfo doc) is the person
> reading/writing the code, and the optimization is the act of choosing
> delete over remove or delq over remq or nconc over append, which is
> exactly what the reader will want to know, I think.
See my other message: I think we are talking about 2 different
things. My gripe was only about using the term "destructive
modification", which muddies the waters without gaining anything.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-08 22:26 ` Drew Adams
2012-09-09 3:00 ` Eli Zaretskii
@ 2012-09-10 11:54 ` Wolfgang Jenkner
1 sibling, 0 replies; 37+ messages in thread
From: Wolfgang Jenkner @ 2012-09-10 11:54 UTC (permalink / raw
To: Drew Adams; +Cc: 12314, cyd
On Sun, Sep 09 2012, Drew Adams wrote:
>> 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.
>
> 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)
Though using `delete' and friends this way would have unpredictable
results in ANSI Common Lisp[1] or Scheme (delete! in srfi1[2]), hence
may be regarded as questionable programming style in Emacs Lisp as well,
which I understand is Eli's point.
The following should work in both CL (except for the missing DEFVARs)
and Emacs Lisp, but sort of defeats the point about easy sharing ;-)
(setq a (list 1 2 3 4))
(setq b (cddr a))
(setf (cddr a) (setq b (delete 4 b)))
[1] http://www.lispworks.com/documentation/HyperSpec/Body/f_rm_rm.htm#delete
http://www.lispworks.com/documentation/HyperSpec/Issues/iss293_w.htm
[2] http://srfi.schemers.org/srfi-1/srfi-1.html#LinearUpdateProcedures
Wolfgang
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-10 4:37 ` Eli Zaretskii
@ 2012-09-10 12:59 ` Stefan Monnier
2012-09-10 15:01 ` Stefan Monnier
` (2 more replies)
0 siblings, 3 replies; 37+ messages in thread
From: Stefan Monnier @ 2012-09-10 12:59 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314, cyd
> See my other message: I think we are talking about 2 different
> things. My gripe was only about using the term "destructive
> modification", which muddies the waters without gaining anything.
I don't know, to me "destructive modification" sounds like a very clear
term explaining the general kind of danger we're up against (the kind
that's summarized in Scheme by adding a "!" at the end of the
identifier).
Stefan
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-10 12:59 ` Stefan Monnier
@ 2012-09-10 15:01 ` Stefan Monnier
2012-09-10 15:21 ` Drew Adams
2012-09-10 16:24 ` Eli Zaretskii
2 siblings, 0 replies; 37+ messages in thread
From: Stefan Monnier @ 2012-09-10 15:01 UTC (permalink / raw
To: Eli Zaretskii; +Cc: 12314, cyd
>> See my other message: I think we are talking about 2 different
>> things. My gripe was only about using the term "destructive
>> modification", which muddies the waters without gaining anything.
> I don't know, to me "destructive modification" sounds like a very clear
> term explaining the general kind of danger we're up against (the kind
> that's summarized in Scheme by adding a "!" at the end of the
> identifier).
This said, we could use some other "equivalent" term, such as "side
effect", "imperative", "impure", ...
Stefan
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-10 12:59 ` Stefan Monnier
2012-09-10 15:01 ` Stefan Monnier
@ 2012-09-10 15:21 ` Drew Adams
2012-09-10 16:24 ` Eli Zaretskii
2 siblings, 0 replies; 37+ messages in thread
From: Drew Adams @ 2012-09-10 15:21 UTC (permalink / raw
To: 'Stefan Monnier', 'Eli Zaretskii'; +Cc: 12314, cyd
> > My gripe was only about using the term "destructive
> > modification", which muddies the waters without gaining anything.
>
> I don't know, to me "destructive modification" sounds like a
> very clear term explaining the general kind of danger we're up
> against (the kind that's summarized in Scheme by adding a "!" at
> the end of the identifier).
The term itself does not _explain_ the danger, but it does suggest some danger.
Strictly speaking, "destructive modification" is redundant - all modification
replaces one state by another: it destroys an old state and creates a new one.
But Lisp being entre deux chaises (functional, imperative/procedural), and given
the existence of similar-sounding Lisp functions such as `remove' and `delete',
it is worth emphasizing the difference (for the doc of both `remove' and
`delete').
For the non-modifying one, we point out explicitly that it is "non-destructive".
For the modifying one, we point out explicitly that it modifies something, as a
side effect, and we (conventionally, in Lisp jargon) call it "destructive".
It's about the doc being not only correct but also more helpful. Sometimes a
bit of redundancy has pedagogical merit. Sometimes redundancy is just noise to
wade through. Here, specifically because of the "danger"/gotchas, it does not
hurt to add "destructive", IMO.
It is really the names of "non-destructive" functions such as `append' and
`remove' that are misleading. They necessitate our taking pains to explain that
no real modification takes place. Names that better suggest the declarative
nature of such functions might be, say, `concatenation' and `all-but' (or
`removed').
Names such as `append' and `remove' do not describe the result value of the
function. Instead, they describe a modifying operation that might have nothing
to do with the actual implementation (which is not so important here anyway),
and they take emphasis away from what is important for a pure function: the
return value.
But such procedurally oriented naming is pretty common/traditional, even for
applicative languages. And it tends toward shorter, simpler names.
^ permalink raw reply [flat|nested] 37+ messages in thread
* bug#12314: 24.2.50; `add-to-history': use `setq' with `delete'
2012-09-10 12:59 ` Stefan Monnier
2012-09-10 15:01 ` Stefan Monnier
2012-09-10 15:21 ` Drew Adams
@ 2012-09-10 16:24 ` Eli Zaretskii
2 siblings, 0 replies; 37+ messages in thread
From: Eli Zaretskii @ 2012-09-10 16:24 UTC (permalink / raw
To: Stefan Monnier; +Cc: 12314, cyd
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: drew.adams@oracle.com, 12314@debbugs.gnu.org, cyd@gnu.org
> Date: Mon, 10 Sep 2012 08:59:26 -0400
>
> > See my other message: I think we are talking about 2 different
> > things. My gripe was only about using the term "destructive
> > modification", which muddies the waters without gaining anything.
>
> I don't know, to me "destructive modification" sounds like a very clear
> term explaining the general kind of danger we're up against (the kind
> that's summarized in Scheme by adding a "!" at the end of the
> identifier).
Alas, the manual itself gives no basis for such an interpretation. It
says (in two different places):
You can modify the CAR and CDR contents of a cons cell with the
primitives `setcar' and `setcdr'. We call these "destructive"
operations because they change existing list structure.
Here are some functions that rearrange lists "destructively" by
modifying the CDRs of their component cons cells. We call these
functions "destructive" because they chew up the original lists passed
to them as arguments, relinking their cons cells to form a new list that
is the returned value.
The only danger I glean from these is the "danger" of assigning any
meaning to the original list.
^ permalink raw reply [flat|nested] 37+ messages in thread
end of thread, other threads:[~2012-09-10 16:24 UTC | newest]
Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-30 23:08 bug#12314: 24.2.50; `add-to-history': use `setq' with `delete' Drew Adams
2012-09-08 14:32 ` Chong Yidong
2012-09-08 14:43 ` Eli Zaretskii
2012-09-08 14:57 ` Drew Adams
2012-09-08 15:20 ` Eli Zaretskii
2012-09-08 15:48 ` Drew Adams
2012-09-08 16:05 ` Eli Zaretskii
2012-09-08 16:19 ` Andreas Schwab
2012-09-08 16:33 ` Eli Zaretskii
2012-09-08 16:50 ` Lars Ingebrigtsen
2012-09-08 16:54 ` Drew Adams
2012-09-08 17:06 ` Andreas Schwab
2012-09-08 16:35 ` Drew Adams
2012-09-08 16:25 ` Drew Adams
2012-09-08 16:32 ` Eli Zaretskii
2012-09-08 16:42 ` Drew Adams
2012-09-08 21:21 ` Eli Zaretskii
2012-09-08 22:26 ` Drew Adams
2012-09-09 3:00 ` Eli Zaretskii
2012-09-09 6:29 ` Drew Adams
2012-09-09 7:53 ` Chong Yidong
2012-09-09 17:25 ` Eli Zaretskii
2012-09-10 11:54 ` Wolfgang Jenkner
2012-09-08 23:11 ` Stefan Monnier
2012-09-09 2:51 ` Eli Zaretskii
2012-09-09 14:44 ` Stefan Monnier
2012-09-09 17:14 ` Eli Zaretskii
2012-09-09 17:35 ` Drew Adams
2012-09-09 18:20 ` Eli Zaretskii
2012-09-09 19:46 ` Drew Adams
2012-09-09 21:37 ` Stefan Monnier
2012-09-10 4:37 ` Eli Zaretskii
2012-09-10 12:59 ` Stefan Monnier
2012-09-10 15:01 ` Stefan Monnier
2012-09-10 15:21 ` Drew Adams
2012-09-10 16:24 ` Eli Zaretskii
2012-09-09 8:25 ` Dmitry Gutov
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.