Subject: Re: bug#75170: add-to-alist: new function

From: Eshel Yaron <[email-masked]>
Date: Sun, 29 Dec 2024 08:33:06 +0100

Hello,

Roland Winkler <[email-masked]> 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