* bug#75170: add-to-alist: new function
@ 2024-12-29 5:33 Roland Winkler
2024-12-29 6:34 ` Roland Winkler
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Roland Winkler @ 2024-12-29 5:33 UTC (permalink / raw)
To: 75170
On Mon, 12 Feb 2001, Stephen Gildea wrote:
> Here's a handy function I'd like to see added to Emacs 21: add-to-alist.
> It is like add-to-list, but it looks only at the cars of the element to
> be added and the existing list elements when considering a match. An
> additional optional argument to add-to-alist says what to do if the car
> matches but the cdr does not.
>
> I use this function in my .emacs to update values in alists such as
> default-frame-alist and auto-mode-alist; I'm sure it has other uses.
> My goal in proposing this function is to allow .emacs files to be
> shorter and easier to write. The functions add-to-list and add-hook
> were important steps in that direction; here is another such step.
>
>
> (defun add-to-alist (alist-var elt-cons &optional no-replace)
> "Add to the value of ALIST-VAR an element ELT-CONS if it isn't there yet.
> If an element with the same car as the car of ELT-CONS is already present,
> replace it with ELT-CONS unless NO-REPLACE is non-nil; if a matching
> element is not already present, add ELT-CONS to the front of the alist.
> The test for presence of the car of ELT-CONS is done with `equal'."
> (let ((existing-element (assoc (car elt-cons) (symbol-value alist-var))))
> (if existing-element
> (or no-replace
> (rplacd existing-element (cdr elt-cons)))
> (set alist-var (cons elt-cons (symbol-value alist-var))))))
>
>
> The no-replace argument is useful for setting auto-mode-alist when you
> don't know whether Emacs supports a particular programming language.
> For example, the following suppresses using text-mode for m4 files in
> Emacs 19 but doesn't override using m4-mode in Emacs 20.
>
> (setq default-major-mode 'text-mode)
> (add-to-alist 'auto-mode-alist '("\\.m4\\'" . fundamental-mode) t)
While I thought about a function add-to-alist I found the above thread
from 24 years ago. Stephen's message describes nicely when such a
function can be useful. I suggest to add such a function to subr.el.
The code below follows the conventions of add-to-list.
(defun add-to-alist (alist-var elt-cons &optional no-replace append compare-fn)
"Add ELT-CONS to the value of ALIST-VAR if it isn't there yet.
If an element with the same car as the car of ELT-CONS is already present
in ALIST-VAR, replace it with ELT-CONS unless NO-REPLACE is non-nil.
If a matching element is not yet present, add ELT-CONS at the beginning
of ALIST-VAR. If APPEND is non-nil, add ELT-CONS at the end of ALIST-VAR.
The test for presence of ELT-CONS is done with `equal', or with COMPARE-FN
if that's non-nil.
ALIST-VAR should not refer to a lexical variable.
The return value is the new value of ALIST-VAR."
(let ((elt (cond ((or (null compare-fn) (eq compare-fn #'equal))
(assoc (car elt-cons) (symbol-value alist-var)))
((eq compare-fn #'eq)
(assq (car elt-cons) (symbol-value alist-var)))
(t
(let ((alist (symbol-value alist-var))
(key (car elt-cons)))
(while (and alist
(not (funcall compare-fn key (caar alist))))
(setq alist (cdr alist)))
(car alist))))))
(if elt
(progn
(unless no-replace
(setcdr elt (cdr elt-cons)))
(symbol-value alist-var))
(set alist-var
(if append
(append (symbol-value alist-var) (list elt-cons))
(cons elt-cons (symbol-value alist-var)))))))
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2024-12-29 5:33 bug#75170: add-to-alist: new function Roland Winkler
@ 2024-12-29 6:34 ` Roland Winkler
2024-12-29 7:54 ` Juri Linkov
2024-12-29 7:33 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-29 7:50 ` Eli Zaretskii
2 siblings, 1 reply; 12+ messages in thread
From: Roland Winkler @ 2024-12-29 6:34 UTC (permalink / raw)
To: 75170
On Sat, Dec 28 2024, Roland Winkler wrote:
> On Mon, 12 Feb 2001, Stephen Gildea wrote:
>> Here's a handy function I'd like to see added to Emacs 21:
>> add-to-alist.
I forgot to say: I could not find any follow-up or discussion of
Stephen's proposal
https://lists.gnu.org/archive/html/bug-gnu-emacs/2001-02/msg00066.html
I know about the very different approaches underlying the function
add-to-list compared to the macro pushnew. I followed the design of
add-to-list as I am thinking (like Stephen) of similar use cases.
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2024-12-29 5:33 bug#75170: add-to-alist: new function Roland Winkler
2024-12-29 6:34 ` Roland Winkler
@ 2024-12-29 7:33 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-29 7:50 ` Eli Zaretskii
2 siblings, 0 replies; 12+ messages in thread
From: Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-12-29 7:33 UTC (permalink / raw)
To: Roland Winkler; +Cc: 75170
Hello,
Roland Winkler <winkler@gnu.org> writes:
> On Mon, 12 Feb 2001, Stephen Gildea wrote:
[...]
> While I thought about a function add-to-alist I found the above thread
> from 24 years ago. Stephen's message describes nicely when such a
> function can be useful. I suggest to add such a function to subr.el.
>
> The code below follows the conventions of add-to-list.
>
> (defun add-to-alist (alist-var elt-cons &optional no-replace append compare-fn)
> "Add ELT-CONS to the value of ALIST-VAR if it isn't there yet.
> If an element with the same car as the car of ELT-CONS is already present
> in ALIST-VAR, replace it with ELT-CONS unless NO-REPLACE is non-nil.
> If a matching element is not yet present, add ELT-CONS at the beginning
> of ALIST-VAR. If APPEND is non-nil, add ELT-CONS at the end of ALIST-VAR.
> The test for presence of ELT-CONS is done with `equal', or with COMPARE-FN
> if that's non-nil.
> ALIST-VAR should not refer to a lexical variable.
>
> The return value is the new value of ALIST-VAR."
> (let ((elt (cond ((or (null compare-fn) (eq compare-fn #'equal))
> (assoc (car elt-cons) (symbol-value alist-var)))
> ((eq compare-fn #'eq)
> (assq (car elt-cons) (symbol-value alist-var)))
> (t
> (let ((alist (symbol-value alist-var))
> (key (car elt-cons)))
> (while (and alist
> (not (funcall compare-fn key (caar alist))))
> (setq alist (cdr alist)))
> (car alist))))))
> (if elt
> (progn
> (unless no-replace
> (setcdr elt (cdr elt-cons)))
> (symbol-value alist-var))
> (set alist-var
> (if append
> (append (symbol-value alist-var) (list elt-cons))
> (cons elt-cons (symbol-value alist-var)))))))
FWIW, in my working branch I use alist-set which does something similar,
I think:
--8<---------------cut here---------------start------------->8---
(defun alist-set (key alist value &optional testfn)
"Associate VALUE with KEY in ALIST, comparing keys with TESTFN."
(setf (alist-get key alist nil nil testfn) value))
--8<---------------cut here---------------end--------------->8---
Cheers,
Eshel
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2024-12-29 5:33 bug#75170: add-to-alist: new function Roland Winkler
2024-12-29 6:34 ` Roland Winkler
2024-12-29 7:33 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-29 7:50 ` Eli Zaretskii
2024-12-29 14:50 ` Roland Winkler
2 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2024-12-29 7:50 UTC (permalink / raw)
To: Roland Winkler; +Cc: 75170
> From: Roland Winkler <winkler@gnu.org>
> Date: Sat, 28 Dec 2024 23:33:56 -0600
>
> On Mon, 12 Feb 2001, Stephen Gildea wrote:
> > Here's a handy function I'd like to see added to Emacs 21: add-to-alist.
> > It is like add-to-list, but it looks only at the cars of the element to
> > be added and the existing list elements when considering a match. An
> > additional optional argument to add-to-alist says what to do if the car
> > matches but the cdr does not.
> >
> > I use this function in my .emacs to update values in alists such as
> > default-frame-alist and auto-mode-alist; I'm sure it has other uses.
> > My goal in proposing this function is to allow .emacs files to be
> > shorter and easier to write. The functions add-to-list and add-hook
> > were important steps in that direction; here is another such step.
> >
> >
> > (defun add-to-alist (alist-var elt-cons &optional no-replace)
> > "Add to the value of ALIST-VAR an element ELT-CONS if it isn't there yet.
> > If an element with the same car as the car of ELT-CONS is already present,
> > replace it with ELT-CONS unless NO-REPLACE is non-nil; if a matching
> > element is not already present, add ELT-CONS to the front of the alist.
> > The test for presence of the car of ELT-CONS is done with `equal'."
> > (let ((existing-element (assoc (car elt-cons) (symbol-value alist-var))))
> > (if existing-element
> > (or no-replace
> > (rplacd existing-element (cdr elt-cons)))
> > (set alist-var (cons elt-cons (symbol-value alist-var))))))
> >
> >
> > The no-replace argument is useful for setting auto-mode-alist when you
> > don't know whether Emacs supports a particular programming language.
> > For example, the following suppresses using text-mode for m4 files in
> > Emacs 19 but doesn't override using m4-mode in Emacs 20.
> >
> > (setq default-major-mode 'text-mode)
> > (add-to-alist 'auto-mode-alist '("\\.m4\\'" . fundamental-mode) t)
>
> While I thought about a function add-to-alist I found the above thread
> from 24 years ago. Stephen's message describes nicely when such a
> function can be useful. I suggest to add such a function to subr.el.
>
> The code below follows the conventions of add-to-list.
>
> (defun add-to-alist (alist-var elt-cons &optional no-replace append compare-fn)
> "Add ELT-CONS to the value of ALIST-VAR if it isn't there yet.
> If an element with the same car as the car of ELT-CONS is already present
> in ALIST-VAR, replace it with ELT-CONS unless NO-REPLACE is non-nil.
> If a matching element is not yet present, add ELT-CONS at the beginning
> of ALIST-VAR. If APPEND is non-nil, add ELT-CONS at the end of ALIST-VAR.
> The test for presence of ELT-CONS is done with `equal', or with COMPARE-FN
> if that's non-nil.
> ALIST-VAR should not refer to a lexical variable.
Thanks.
What is the advantage of adding this function, given that add-to-list
can be used with alists, and given that alist-get can nowadays be used
as a generalize variable?
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2024-12-29 7:50 ` Eli Zaretskii
@ 2024-12-29 14:50 ` Roland Winkler
2025-01-05 15:21 ` Eli Zaretskii
2025-01-19 2:20 ` Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 2 replies; 12+ messages in thread
From: Roland Winkler @ 2024-12-29 14:50 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: 75170
On Sun, Dec 29 2024, Eli Zaretskii wrote:
> What is the advantage of adding this function, given that add-to-list
> can be used with alists, and given that alist-get can nowadays be used
> as a generalize variable?
The advantage I see for also having the function add-to-alist is the
following:
add-to-list checks for the presence of an element in a list. In the
case of alists, this means it checks for the presence of associations.
You cannot easily modify an existing association with add-to-list. If
you have an alist with association (foo . bar) and you call add-to-list
with an element (foo . baz), add-to-list will not remove the association
(foo . bar), but the alist will then contain both associations.
add-to-alist checks for the presence of keys and it makes sure that each
key appears only once in an alist. By default, it replaces the value of
an existing key. This makes it easy to modify an existing association.
Only with the optional arg NO-REPLACE non-nil, it will preserve an
existing association.
Say, I want in my .emacs file a more complicated association for a key,
and I do not get initially what I want. I can call add-to-alist
multiple times, till I get what I want.
Is there a simple way to accomplish this in other ways (a way that we
recommend for users in their init file if they do not want to use
customize like me)?
Would it make sense to give this functions a different name if more
often it may be used to modify existing associations in an alist instead
of adding new ones?
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2024-12-29 14:50 ` Roland Winkler
@ 2025-01-05 15:21 ` Eli Zaretskii
2025-01-18 9:33 ` Eli Zaretskii
2025-01-19 11:23 ` Stefan Kangas
2025-01-19 2:20 ` Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 2 replies; 12+ messages in thread
From: Eli Zaretskii @ 2025-01-05 15:21 UTC (permalink / raw)
To: Roland Winkler, Stefan Kangas, Andrea Corallo; +Cc: 75170
> From: Roland Winkler <winkler@gnu.org>
> Cc: 75170@debbugs.gnu.org
> Date: Sun, 29 Dec 2024 08:50:18 -0600
>
> On Sun, Dec 29 2024, Eli Zaretskii wrote:
> > What is the advantage of adding this function, given that add-to-list
> > can be used with alists, and given that alist-get can nowadays be used
> > as a generalize variable?
>
> The advantage I see for also having the function add-to-alist is the
> following:
>
> add-to-list checks for the presence of an element in a list. In the
> case of alists, this means it checks for the presence of associations.
> You cannot easily modify an existing association with add-to-list. If
> you have an alist with association (foo . bar) and you call add-to-list
> with an element (foo . baz), add-to-list will not remove the association
> (foo . bar), but the alist will then contain both associations.
>
> add-to-alist checks for the presence of keys and it makes sure that each
> key appears only once in an alist. By default, it replaces the value of
> an existing key. This makes it easy to modify an existing association.
> Only with the optional arg NO-REPLACE non-nil, it will preserve an
> existing association.
>
> Say, I want in my .emacs file a more complicated association for a key,
> and I do not get initially what I want. I can call add-to-alist
> multiple times, till I get what I want.
>
> Is there a simple way to accomplish this in other ways (a way that we
> recommend for users in their init file if they do not want to use
> customize like me)?
>
> Would it make sense to give this functions a different name if more
> often it may be used to modify existing associations in an alist instead
> of adding new ones?
Let's hear the other co-maintainers.
Stefan and Andrea, WDYT about this? Should we add this function?
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2025-01-05 15:21 ` Eli Zaretskii
@ 2025-01-18 9:33 ` Eli Zaretskii
2025-01-19 11:23 ` Stefan Kangas
1 sibling, 0 replies; 12+ messages in thread
From: Eli Zaretskii @ 2025-01-18 9:33 UTC (permalink / raw)
To: stefankangas, acorallo; +Cc: 75170, winkler
Ping!
> Cc: 75170@debbugs.gnu.org
> Date: Sun, 05 Jan 2025 17:21:00 +0200
> From: Eli Zaretskii <eliz@gnu.org>
>
> > From: Roland Winkler <winkler@gnu.org>
> > Cc: 75170@debbugs.gnu.org
> > Date: Sun, 29 Dec 2024 08:50:18 -0600
> >
> > On Sun, Dec 29 2024, Eli Zaretskii wrote:
> > > What is the advantage of adding this function, given that add-to-list
> > > can be used with alists, and given that alist-get can nowadays be used
> > > as a generalize variable?
> >
> > The advantage I see for also having the function add-to-alist is the
> > following:
> >
> > add-to-list checks for the presence of an element in a list. In the
> > case of alists, this means it checks for the presence of associations.
> > You cannot easily modify an existing association with add-to-list. If
> > you have an alist with association (foo . bar) and you call add-to-list
> > with an element (foo . baz), add-to-list will not remove the association
> > (foo . bar), but the alist will then contain both associations.
> >
> > add-to-alist checks for the presence of keys and it makes sure that each
> > key appears only once in an alist. By default, it replaces the value of
> > an existing key. This makes it easy to modify an existing association.
> > Only with the optional arg NO-REPLACE non-nil, it will preserve an
> > existing association.
> >
> > Say, I want in my .emacs file a more complicated association for a key,
> > and I do not get initially what I want. I can call add-to-alist
> > multiple times, till I get what I want.
> >
> > Is there a simple way to accomplish this in other ways (a way that we
> > recommend for users in their init file if they do not want to use
> > customize like me)?
> >
> > Would it make sense to give this functions a different name if more
> > often it may be used to modify existing associations in an alist instead
> > of adding new ones?
>
> Let's hear the other co-maintainers.
>
> Stefan and Andrea, WDYT about this? Should we add this function?
>
>
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2025-01-05 15:21 ` Eli Zaretskii
2025-01-18 9:33 ` Eli Zaretskii
@ 2025-01-19 11:23 ` Stefan Kangas
1 sibling, 0 replies; 12+ messages in thread
From: Stefan Kangas @ 2025-01-19 11:23 UTC (permalink / raw)
To: Eli Zaretskii, Roland Winkler, Andrea Corallo; +Cc: 75170
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Roland Winkler <winkler@gnu.org>
>> Cc: 75170@debbugs.gnu.org
>> Date: Sun, 29 Dec 2024 08:50:18 -0600
>>
>> On Sun, Dec 29 2024, Eli Zaretskii wrote:
>> > What is the advantage of adding this function, given that add-to-list
>> > can be used with alists, and given that alist-get can nowadays be used
>> > as a generalize variable?
>>
>> The advantage I see for also having the function add-to-alist is the
>> following:
>>
>> add-to-list checks for the presence of an element in a list. In the
>> case of alists, this means it checks for the presence of associations.
>> You cannot easily modify an existing association with add-to-list. If
>> you have an alist with association (foo . bar) and you call add-to-list
>> with an element (foo . baz), add-to-list will not remove the association
>> (foo . bar), but the alist will then contain both associations.
>>
>> add-to-alist checks for the presence of keys and it makes sure that each
>> key appears only once in an alist. By default, it replaces the value of
>> an existing key. This makes it easy to modify an existing association.
>> Only with the optional arg NO-REPLACE non-nil, it will preserve an
>> existing association.
>>
>> Say, I want in my .emacs file a more complicated association for a key,
>> and I do not get initially what I want. I can call add-to-alist
>> multiple times, till I get what I want.
>>
>> Is there a simple way to accomplish this in other ways (a way that we
>> recommend for users in their init file if they do not want to use
>> customize like me)?
>>
>> Would it make sense to give this functions a different name if more
>> often it may be used to modify existing associations in an alist instead
>> of adding new ones?
>
> Let's hear the other co-maintainers.
>
> Stefan and Andrea, WDYT about this? Should we add this function?
The benefit here is that users could more easily replace associations in
alists. Superfluous associations are not the end of the world, as
`alist-get' will anyways only get the first one, but users might not
know that, and it's less aesthetically pleasing.
If Emacs Lisp was just a programming system, then I would be against
this addition as redundant. Since a small subset of ELisp is also used
as a kind of "customization language", I think it occasionally makes
sense to introduce even redundant constructs, provided that it makes
said customization easier. I think this might be one such example.
On balance, I think we could add it.
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2024-12-29 14:50 ` Roland Winkler
2025-01-05 15:21 ` Eli Zaretskii
@ 2025-01-19 2:20 ` Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-19 6:17 ` Roland Winkler
1 sibling, 1 reply; 12+ messages in thread
From: Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2025-01-19 2:20 UTC (permalink / raw)
To: Roland Winkler; +Cc: Eli Zaretskii, 75170
Roland Winkler <winkler@gnu.org> writes:
> Is there a simple way to accomplish this in other ways (a way that we
> recommend for users in their init file if they do not want to use
> customize like me)?
We indeed recommend using (setf (alist-get ...)), IIUC this is _exactly_
what you were looking for. Your patch contains an implementation of the
setter of `alist-get', and we would add a duplication.
If you did not find this thing, maybe we need to add a hint to some
chapter of the manual?
Michael.
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#75170: add-to-alist: new function
2025-01-19 2:20 ` Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2025-01-19 6:17 ` Roland Winkler
0 siblings, 0 replies; 12+ messages in thread
From: Roland Winkler @ 2025-01-19 6:17 UTC (permalink / raw)
To: Michael Heerdegen; +Cc: Eli Zaretskii, 75170
On Sun, Jan 19 2025, Michael Heerdegen wrote:
>> Is there a simple way to accomplish this in other ways (a way that we
>> recommend for users in their init file if they do not want to use
>> customize like me)?
>
> We indeed recommend using (setf (alist-get ...)), IIUC this is _exactly_
> what you were looking for. Your patch contains an implementation of the
> setter of `alist-get', and we would add a duplication.
>
> If you did not find this thing, maybe we need to add a hint to some
> chapter of the manual?
Great! -- It seems, indeed, the code I am looking for does (mostly, see
below) exist. But the "We indeed recommend using..." can be improved.
It should appear at a spot where not only advanced elisp hackers may
have a chance of finding it. But more average users should be able to
find it, too (say, as a strategy for modifying alists in the emacs init
file).
I just noticed: the docstring of alist-get is much more verbose
regarding how this function can be combined with setf than the elisp
manual. So extending the documentation of alist-get in the elisp manual
can already make a big difference! Personally, I always find typical
usage examples in the elisp manual most helpful.
Actually, I just read the docstring from alist-get a couple of times.
And the meaning of the optional arg REMOVE is not clear to me: what is
the "new value" of an association if the key is removed from the alist?
Also, it seems to me there is a difference between add-to-alist and
(setf (alist-get ...)). It was already Stephen Gildea's original
proposal from long time ago to give this function an optional arg
NO-REPLACE, and his proposal included a nice example for when this can
be useful (copied in my first posting). It seems to me that
(setf (alist-get ...)) has no equivalent of NO-REPLACE. Personally,
I have not run in a situation when I had needed this arg; but I can
imagine that it would help others.
Roland
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-01-19 11:23 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-29 5:33 bug#75170: add-to-alist: new function Roland Winkler
2024-12-29 6:34 ` Roland Winkler
2024-12-29 7:54 ` Juri Linkov
2024-12-29 14:54 ` Roland Winkler
2024-12-29 7:33 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-29 7:50 ` Eli Zaretskii
2024-12-29 14:50 ` Roland Winkler
2025-01-05 15:21 ` Eli Zaretskii
2025-01-18 9:33 ` Eli Zaretskii
2025-01-19 11:23 ` Stefan Kangas
2025-01-19 2:20 ` Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors
2025-01-19 6:17 ` Roland Winkler
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.