Subject: Re: bug#25929: 25.2; map-delete doesn't delete permanently 1st alist elt

From: Nicolas Petton <[email-masked]>
Date: Thu, 02 Mar 2017 11:59:08 +0100

Tino Calancha <[email-masked]> writes:

> (cl-loop for i below 3 collect
>   (let ((map (list (cons 0 3)
>                    (cons 1 4)
>                    (cons 2 5))))
>     (map-delete map i)
>     (null (map-elt map i))))
> => (nil t t) ; The first pair, i.e. '(0 . 3) is not permanently deleted.
>
> I've used the word 'permantly' because it seems it is temporary
> deleted:
>
> (cl-loop for i below 3 collect
>   (let ((map (list (cons 0 3)
>                    (cons 1 4)
>                    (cons 2 5))))
>     (null (map-elt
>            (map-delete map i)
>            i))))
> => (t t t)

The alist is indeed modified within the `map-delete' function, but in an
unexpected way: if the first key is deleted, the variable `map' is
`setq'ed, which has no effect outside of the function.

One fix would be to make `map-delete' a macro:

(defmacro map-delete (map key)
  "Delete KEY from MAP and return MAP.
No error is signaled if KEY is not a key of MAP.  If MAP is an
array, store nil at the index KEY.

  MAP can be a list, hash-table or array."
    `(macroexp-let2 nil key
       (map--dispatch ,map
         :list (setf (alist-get ,key ,map nil t) nil)
         :hash-table (remhash ,key ,map)
         :array (and (>= ,key 0)
                     (<= ,key (seq-length ,map))
                     (aset ,map ,key nil)))
       ,map))

WDYT?

Cheers,
Nico