* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
@ 2014-08-02 21:55 Ivan Shmakov
2014-08-03 0:55 ` Drew Adams
2014-08-06 17:26 ` Stefan Monnier
0 siblings, 2 replies; 10+ messages in thread
From: Ivan Shmakov @ 2014-08-02 21:55 UTC (permalink / raw)
To: 18175
[-- Attachment #1: Type: text/plain, Size: 641 bytes --]
Package: emacs
Severity: wishlist
Given that switch-to-buffer returns its argument, /and/ given
that mapc returns the sequence it’s given, I suggest that the
(mapcar 'switch-to-buffer LIST) forms in lisp/files.el be
replaced with (mapc 'switch-to-buffer LIST), – if only to avoid
the unnecessary consing when the list is effectively copied in
the mapcar case.
The lists mapcar is applied to in such cases are returned from
find-file-noselect, and so, as it seems, are “fresh” ones
anyway.
A possible patch is MIMEd.
--
FSF associate member #7257 http://boycottsystemd.org/ … 3013 B6A0 230E 334A
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-diff, Size: 1257 bytes --]
diff --git a/lisp/files.el b/lisp/files.el
index 9272e98..e604ce7 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1428,7 +1428,7 @@ automatically choosing a major mode, use \\[find-file-literally]."
(confirm-nonexistent-file-or-buffer)))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
- (mapcar 'switch-to-buffer (nreverse value))
+ (mapc 'switch-to-buffer (nreverse value))
(switch-to-buffer value))))
(defun find-file-other-window (filename &optional wildcards)
@@ -1451,7 +1451,7 @@ expand wildcards (if any) and visit multiple files."
(progn
(setq value (nreverse value))
(cons (switch-to-buffer-other-window (car value))
- (mapcar 'switch-to-buffer (cdr value))))
+ (mapc 'switch-to-buffer (cdr value))))
(switch-to-buffer-other-window value))))
(defun find-file-other-frame (filename &optional wildcards)
@@ -1474,7 +1474,7 @@ expand wildcards (if any) and visit multiple files."
(progn
(setq value (nreverse value))
(cons (switch-to-buffer-other-frame (car value))
- (mapcar 'switch-to-buffer (cdr value))))
+ (mapc 'switch-to-buffer (cdr value))))
(switch-to-buffer-other-frame value))))
(defun find-file-existing (filename)
^ permalink raw reply related [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-02 21:55 bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...) Ivan Shmakov
@ 2014-08-03 0:55 ` Drew Adams
2014-08-03 8:55 ` Ivan Shmakov
2014-08-06 17:26 ` Stefan Monnier
1 sibling, 1 reply; 10+ messages in thread
From: Drew Adams @ 2014-08-03 0:55 UTC (permalink / raw)
To: Ivan Shmakov, 18175
> Given that switch-to-buffer returns its argument, /and/ given
> that mapc returns the sequence it’s given, I suggest that the
> (mapcar 'switch-to-buffer LIST) forms in lisp/files.el be
> replaced with (mapc 'switch-to-buffer LIST), – if only to avoid
> the unnecessary consing when the list is effectively copied in
> the mapcar case.
>
> The lists mapcar is applied to in such cases are returned from
> find-file-noselect, and so, as it seems, are “fresh” ones
> anyway.
Not a good idea, IMHO.
It's not just about performance; it's about coding style.
By using `mapcar' you are signaling that you are interested in the return values of the argument function (and of course the resulting list of them).
By using `mapc' you are signaling that the values returned by the argument function are unimportant (only its side effects are significant).
If you want to improve the performance, and that is the only change you want to make, then please consider another approach.
^ permalink raw reply [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-03 0:55 ` Drew Adams
@ 2014-08-03 8:55 ` Ivan Shmakov
2014-08-03 16:32 ` Drew Adams
0 siblings, 1 reply; 10+ messages in thread
From: Ivan Shmakov @ 2014-08-03 8:55 UTC (permalink / raw)
To: 18175
[-- Attachment #1: Type: text/plain, Size: 1476 bytes --]
>>>>> Drew Adams <drew.adams@oracle.com> writes:
>> Given that switch-to-buffer returns its argument, /and/ given that
>> mapc returns the sequence it’s given, I suggest that the
>> (mapcar 'switch-to-buffer LIST) forms in lisp/files.el be replaced
>> with (mapc 'switch-to-buffer LIST), – if only to avoid the
>> unnecessary consing when the list is effectively copied in the
>> mapcar case.
>> The lists mapcar is applied to in such cases are returned from
>> find-file-noselect, and so, as it seems, are “fresh” ones anyway.
> Not a good idea, IMHO.
> It's not just about performance; it's about coding style.
> By using `mapcar' you are signaling that you are interested in the
> return values of the argument function (and of course the resulting
> list of them).
> By using `mapc' you are signaling that the values returned by the
> argument function are unimportant (only its side effects are
> significant).
How do you signal that the values returned by the argument
function are unimportant, /and/ that you’re interested in the
/original/ list instead?
> If you want to improve the performance, and that is the only change
> you want to make, then please consider another approach.
Please consider the patch MIMEd. FWIW, it avoids one more cons
in both find-file-other-window and find-file-other-frame.
--
FSF associate member #7257 http://boycottsystemd.org/ … 3013 B6A0 230E 334A
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-diff, Size: 1752 bytes --]
diff --git a/lisp/files.el b/lisp/files.el
index 9272e98..c3a6f0d 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1428,7 +1428,7 @@ automatically choosing a major mode, use \\[find-file-literally]."
(confirm-nonexistent-file-or-buffer)))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
- (mapcar 'switch-to-buffer (nreverse value))
+ (mapc 'switch-to-buffer (nreverse value))
(switch-to-buffer value))))
(defun find-file-other-window (filename &optional wildcards)
@@ -1448,10 +1448,10 @@ expand wildcards (if any) and visit multiple files."
(confirm-nonexistent-file-or-buffer)))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
- (progn
- (setq value (nreverse value))
- (cons (switch-to-buffer-other-window (car value))
- (mapcar 'switch-to-buffer (cdr value))))
+ (prog1
+ (setq value (nreverse value))
+ (switch-to-buffer-other-window (car value))
+ (mapc 'switch-to-buffer (cdr value)))
(switch-to-buffer-other-window value))))
(defun find-file-other-frame (filename &optional wildcards)
@@ -1471,10 +1471,10 @@ expand wildcards (if any) and visit multiple files."
(confirm-nonexistent-file-or-buffer)))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
- (progn
- (setq value (nreverse value))
- (cons (switch-to-buffer-other-frame (car value))
- (mapcar 'switch-to-buffer (cdr value))))
+ (prog1
+ (setq value (nreverse value))
+ (switch-to-buffer-other-frame (car value))
+ (mapc 'switch-to-buffer (cdr value)))
(switch-to-buffer-other-frame value))))
(defun find-file-existing (filename)
^ permalink raw reply related [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-03 8:55 ` Ivan Shmakov
@ 2014-08-03 16:32 ` Drew Adams
2014-08-03 18:25 ` Ivan Shmakov
0 siblings, 1 reply; 10+ messages in thread
From: Drew Adams @ 2014-08-03 16:32 UTC (permalink / raw)
To: Ivan Shmakov, 18175
> > By using `mapcar' you are signaling that you are interested in the
> > return values of the argument function (and of course the resulting
> > list of them).
>
> > By using `mapc' you are signaling that the values returned by the
> > argument function are unimportant (only its side effects are
> > significant).
>
> How do you signal that the values returned by the argument
> function are unimportant, /and/ that you’re interested in the
> /original/ list instead?
By doing what you've done now. Neither `mapc' nor `mapcar' says
that, on its own.
If return values are not important in some code then `mapc`,
`dolist`, `while`, or any number of other imperative/procedural
approaches are fine to use, and are often preferable.
Looking briefly at the original code and your patches now, I am
reminded that `find-file*' needs to return the list of buffers
(or the single buffer, for that case). (As one user, for example,
I have code that expects the list of buffers to be returned.)
Your new patch does that, and it looks OK to me. I did not spend
much time looking things over, so I might be missing something,
but it looks like you are not changing the external behavior (good).
It is fine to optimize things, but function interfaces (signatures
and behavior as viewed by calling functions or by users) should
not be altered.
You might want to make sure that the list of buffers returned is
the same in all cases as what is returned today. The doc string
of `switch-to-buffer', for instance, seems to make a point of
saying that it returns the buffer switched to. It does not say
that it returns the buffer indicated by argument BUFFER-OR-NAME.
Dunno why, but it does.
I'm guessing that that can make a difference only if the intended
buffer cannot be switched to (an error is raised). And in that
case I'm guessing that the error raised would be handled
correctly by `find-file*'. (I have not checked.)
You might also want to check to be sure that the effect on what
`buffer-list' returns (after the calls to `switch-buffer*')
remains the same.
The calls to `switch-to-buffer*' here do not use non-nil NORECORD,
so that at least can be ignored. But maybe take a look, to make
sure. Some commands and other functions depend on the buffer
order in `buffer-list', so this too should not be altered by
your proposed change.
^ permalink raw reply [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-03 16:32 ` Drew Adams
@ 2014-08-03 18:25 ` Ivan Shmakov
2014-08-03 18:43 ` Drew Adams
0 siblings, 1 reply; 10+ messages in thread
From: Ivan Shmakov @ 2014-08-03 18:25 UTC (permalink / raw)
To: 18175
>>>>> Drew Adams <drew.adams@oracle.com> writes:
[…]
> Your new patch does that, and it looks OK to me. I did not spend
> much time looking things over, so I might be missing something, but
> it looks like you are not changing the external behavior (good).
> It is fine to optimize things, but function interfaces (signatures
> and behavior as viewed by calling functions or by users) should not
> be altered.
I expect neither of these patches to change the external
behavior.
> You might want to make sure that the list of buffers returned is the
> same in all cases as what is returned today. The doc string of
> `switch-to-buffer', for instance, seems to make a point of saying
> that it returns the buffer switched to. It does not say that it
> returns the buffer indicated by argument BUFFER-OR-NAME. Dunno why,
> but it does.
I guess it’s because switch-to-buffer passes its argument
through window-normalize-buffer-to-switch-to, which passes it
through get-buffer in turn. The docstring for the latter reads:
… If BUFFER-OR-NAME is a buffer, return it as given.
And I see no reason for a buffer /name/ to ever appear in the
lists returned from find-file-noselect.
> I'm guessing that that can make a difference only if the intended
> buffer cannot be switched to (an error is raised). And in that case
> I'm guessing that the error raised would be handled correctly by
> `find-file*'. (I have not checked.)
As there’re no condition-case forms around switch-to-buffer
calls in find-file et al. – no such error will be handled in any
special way, and will just be signalled to the user as usual.
> You might also want to check to be sure that the effect on what
> `buffer-list' returns (after the calls to `switch-buffer*') remains
> the same.
AIUI, the buffer-list result depends solely on the order of
calls to switch-to-buffer, which is /not/ changed in any way.
> The calls to `switch-to-buffer*' here do not use non-nil NORECORD, so
> that at least can be ignored. But maybe take a look, to make sure.
> Some commands and other functions depend on the buffer order in
> `buffer-list', so this too should not be altered by your proposed
> change.
--
FSF associate member #7257 http://boycottsystemd.org/ … 3013 B6A0 230E 334A
^ permalink raw reply [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-03 18:25 ` Ivan Shmakov
@ 2014-08-03 18:43 ` Drew Adams
0 siblings, 0 replies; 10+ messages in thread
From: Drew Adams @ 2014-08-03 18:43 UTC (permalink / raw)
To: Ivan Shmakov, 18175
> The docstring for the latter reads:
> … If BUFFER-OR-NAME is a buffer, return it as given.
> And I see no reason for a buffer /name/ to ever appear in the
> lists returned from find-file-noselect.
Yes, of course not. It needs to return a list of buffers. That's why I
wrote that we need to "make sure that the list of buffers returned is
the same in all cases as what is returned today." ^^^^^^^
> > I'm guessing that that can make a difference only if the intended
> > buffer cannot be switched to (an error is raised). And in that case
> > I'm guessing that the error raised would be handled correctly by
> > `find-file*'. (I have not checked.)
>
> As there’re no condition-case forms around switch-to-buffer
> calls in find-file et al. – no such error will be handled in any
> special way, and will just be signalled to the user as usual.
That all I meant by handled (treated) by `find-file*', not that
there is a `condition-case' with a handler. The point is that the
behavior should remain the same; that's all. If it does, fine.
> > You might also want to check to be sure that the effect on what
> > `buffer-list' returns (after the calls to `switch-buffer*') remains
> > the same.
>
> AIUI, the buffer-list result depends solely on the order of
> calls to switch-to-buffer, which is /not/ changed in any way.
>
> > The calls to `switch-to-buffer*' here do not use non-nil NORECORD, so
> > that at least can be ignored. But maybe take a look, to make sure.
> > Some commands and other functions depend on the buffer order in
> > `buffer-list', so this too should not be altered by your proposed
> > change.
Thanks for looking at and testing these things.
^ permalink raw reply [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-02 21:55 bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...) Ivan Shmakov
2014-08-03 0:55 ` Drew Adams
@ 2014-08-06 17:26 ` Stefan Monnier
2014-08-07 19:15 ` Ivan Shmakov
1 sibling, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2014-08-06 17:26 UTC (permalink / raw)
To: Ivan Shmakov; +Cc: 18175
> Given that switch-to-buffer returns its argument, /and/ given
> that mapc returns the sequence it’s given, I suggest that the
> (mapcar 'switch-to-buffer LIST) forms in lisp/files.el be
> replaced with (mapc 'switch-to-buffer LIST), – if only to avoid
> the unnecessary consing when the list is effectively copied in
> the mapcar case.
Thanks, I think it's indeed a valid/correct optimization, but I really
dislike relying on mapc's return value (it really should not return any
value at all).
In this case, the optimization doesn't seem worth the inconvenient of
having a very unusual code (relying on mapc's return value), since
those few cons cells we save are drowned in the noise of all the
code run by switch-to-buffer.
Stefan
^ permalink raw reply [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-06 17:26 ` Stefan Monnier
@ 2014-08-07 19:15 ` Ivan Shmakov
2014-08-07 19:29 ` Stefan Monnier
0 siblings, 1 reply; 10+ messages in thread
From: Ivan Shmakov @ 2014-08-07 19:15 UTC (permalink / raw)
To: 18175
[-- Attachment #1: Type: text/plain, Size: 1948 bytes --]
>>>>> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>> Given that switch-to-buffer returns its argument, /and/ given that
>> mapc returns the sequence it’s given, I suggest that the (mapcar
>> 'switch-to-buffer LIST) forms in lisp/files.el be replaced with
>> (mapc 'switch-to-buffer LIST), – if only to avoid the unnecessary
>> consing when the list is effectively copied in the mapcar case.
> Thanks, I think it's indeed a valid/correct optimization, but I
> really dislike relying on mapc's return value (it really should not
> return any value at all).
I tend to disagree with that last part, – it seems like a common
idiom for a function (or, generally, – a /form/; setq does that,
for one thing) that’s used “solely” for its side-effects to
return its “primary” argument, thus allowing for easy
“chaining”, like:
(foo (bar 42 (baz data)))
Instead of:
(progn
(foo data)
(bar 42 data)
(baz data))
Or something even more crude, like:
(mapc (lambda (fn)
(if (consp fn)
(apply (car fn) `(,@(cdr fn) ,data))
(funcall fn data)))
'(foo (bar 42) baz))
Surely, ‘mapc’ fits that pattern pretty well; cf.:
(foo (bar 42 (baz lst)))
(foo (mapc 'qux (baz lst)))
> In this case, the optimization doesn't seem worth the inconvenient of
> having a very unusual code (relying on mapc's return value), since
> those few cons cells we save are drowned in the noise of all the code
> run by switch-to-buffer.
Yes. However, I believe that the last two hunks of the one
another variant of the diff (MIMEd) actually make the intent to
return the reverse of the list returned by find-file-noselect
/clearer,/ – although at the expense of adding one extra LoC in
each case.
--
FSF associate member #7257 http://boycottsystemd.org/ … 3013 B6A0 230E 334A
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-diff, Size: 1345 bytes --]
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1428,7 +1428,7 @@ automatically choosing a major mode, use \\[find-file-literally]."
(confirm-nonexistent-file-or-buffer)))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
- (mapcar 'switch-to-buffer (nreverse value))
+ (mapc 'switch-to-buffer (nreverse value))
(switch-to-buffer value))))
(defun find-file-other-window (filename &optional wildcards)
@@ -1450,8 +1450,9 @@ expand wildcards (if any) and visit multiple files."
(if (listp value)
(progn
(setq value (nreverse value))
- (cons (switch-to-buffer-other-window (car value))
- (mapcar 'switch-to-buffer (cdr value))))
+ (switch-to-buffer-other-window (car value))
+ (mapc 'switch-to-buffer (cdr value))
+ value)
(switch-to-buffer-other-window value))))
(defun find-file-other-frame (filename &optional wildcards)
@@ -1473,8 +1474,9 @@ expand wildcards (if any) and visit multiple files."
(if (listp value)
(progn
(setq value (nreverse value))
- (cons (switch-to-buffer-other-frame (car value))
- (mapcar 'switch-to-buffer (cdr value))))
+ (switch-to-buffer-other-frame (car value))
+ (mapc 'switch-to-buffer (cdr value))
+ value)
(switch-to-buffer-other-frame value))))
(defun find-file-existing (filename)
^ permalink raw reply [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-07 19:15 ` Ivan Shmakov
@ 2014-08-07 19:29 ` Stefan Monnier
2015-01-23 15:27 ` Ivan Shmakov
0 siblings, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2014-08-07 19:29 UTC (permalink / raw)
To: Ivan Shmakov; +Cc: 18175
> I tend to disagree with that last part, – it seems like a common
> idiom for a function (or, generally, – a /form/; setq does that,
> for one thing) that’s used “solely” for its side-effects to
> return its “primary” argument, thus allowing for easy
Yes, it's common, but I strongly dislike it.
It's used often enough for `setq' that I consider it to be an exception.
In the case of `mapc' OTOH, I'm pretty sure 99.9% of Elisp coders have no
idea what is the return value of `mapc', so using this return value is
a kind of obfuscation.
> Yes. However, I believe that the last two hunks of the one
> another variant of the diff (MIMEd) actually make the intent to
> return the reverse of the list returned by find-file-noselect
> /clearer,/ – although at the expense of adding one extra LoC in
> each case.
Agreed, and neither relies on the return value of `mapc', so those two
hunks are indeed good. Please install them.
Stefan
^ permalink raw reply [flat|nested] 10+ messages in thread
* bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...)
2014-08-07 19:29 ` Stefan Monnier
@ 2015-01-23 15:27 ` Ivan Shmakov
0 siblings, 0 replies; 10+ messages in thread
From: Ivan Shmakov @ 2015-01-23 15:27 UTC (permalink / raw)
To: 18175-done
Version: 25.1
>>>>> Stefan Monnier <monnier@iro.umontreal.ca> writes:
[…]
>> However, I believe that the last two hunks of the one another
>> variant of the diff (MIMEd) actually make the intent to return the
>> reverse of the list returned by find-file-noselect /clearer,/ –
>> although at the expense of adding one extra LoC in each case.
> Agreed, and neither relies on the return value of `mapc', so those
> two hunks are indeed good. Please install them.
Done; closing.
commit 3e824b05af3a75768a61001fad68e2340af810eb
CommitDate: 2015-01-17 19:33:08 +0000
Avoid mapcar in two cases in files.el.
* lisp/files.el (find-file-other-window, find-file-other-frame):
Use mapc instead of mapcar.
Fixes: debbugs:18175
--
FSF associate member #7257 np. Chemical Wedding – Bruce Dickinson 230E 334A
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-01-23 15:27 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-02 21:55 bug#18175: files.el: use mapc in (mapcar 'switch-to-buffer ...) Ivan Shmakov
2014-08-03 0:55 ` Drew Adams
2014-08-03 8:55 ` Ivan Shmakov
2014-08-03 16:32 ` Drew Adams
2014-08-03 18:25 ` Ivan Shmakov
2014-08-03 18:43 ` Drew Adams
2014-08-06 17:26 ` Stefan Monnier
2014-08-07 19:15 ` Ivan Shmakov
2014-08-07 19:29 ` Stefan Monnier
2015-01-23 15:27 ` Ivan Shmakov
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).