2
(setq ali '())
>>> nil
(cl-incf (alist-get 'a ali 0))
>>> ((a . 1))
(setf (alist-get 'b ali) 0)
>>> ((b . 0) (a . 1))
(cl-incf (alist-get 'b ali 0))
>>> 1

As you can see, cl-incf returns different kinds of values in the second and the fourth expressions.

cl-incf per documentation is supposed to return "the incremented value of PLACE", however as we can see with the key 'a it returns the whole ali structure. If we macroexpand it a few times, it's clear what's happening:

(let*
    ((p
      (if
          (and nil
               (not
                (eq nil 'eq)))
          (assoc 'a ali nil)
        (assq 'a ali)))
     (v
      (+
       (if p
           (cdr p)
         0)
       1)))
  (if p
      (setcdr p v)
    (setq ali
          (cons
           (setq p
                 (cons 'a v))
           ali))))

The last setq is applied to ali, so it returns the new value of ali.

It seems to be a bug in the alist generalized variable definition.

Am I correct? If so, how to report it? If not, what's the idiomatic way to work around it, preferably not calling alist-get two times?

8
  • Yep, the behavior for the second sexp, (cl-incf (alist-get 'a ali 0)) looks wrong. Consider filing a bug report: M-x report-emacs-bug.
    – Drew
    Aug 12, 2020 at 20:29
  • I think the last part of the expansion should be something like this: (if p (setcdr p v) (setq ali (cons (setq p (cons 'a v)) ali)) v). IOW, after updating ali it should return v, not ali. In all cases it should return v.
    – Drew
    Aug 12, 2020 at 20:41
  • I went ahead and filed bug report #42837 for this. Wasn't sure you'd do it, and wanted to get it done. Feel free to chime in there.
    – Drew
    Aug 12, 2020 at 22:57
  • Emacs 27.1's return value is correct, in other words, for your seconds expression, it returns 1 instead of ((a . 1)). I don't have Emacs 26.3 installed, so I can't test that version.
    – xuchunyang
    Aug 13, 2020 at 3:45
  • @Drew thank you for filing the report, it's okay that you did it.
    – Artem Yu
    Aug 13, 2020 at 8:42

1 Answer 1

2

Yep, the behavior for the second sexp, (cl-incf (alist-get 'a ali 0)) looks wrong. I think the last part of the expansion should be something like this:

(if p
    (setcdr p v)
  (setq ali (cons (setq p (cons 'a v)) ali))
  v)

IOW, after updating ali it should return v, not ali. In all cases it should return v.

I filed Emacs bug #42837 for this. In the future, you can do it yourself via report-emacs-bug.

But it turns out this has already been fixed in Emacs 27.1, which has just been released.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.