GNU bug report logs - #62068
29.0.60; map-elt and map-insert for nested structures

Previous Next

Package: emacs;

Reported by: Augusto Stoffel <arstoffel <at> gmail.com>

Date: Thu, 9 Mar 2023 08:17:02 UTC

Severity: normal

Found in version 29.0.60

To reply to this bug, email your comments to 62068 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to contovob <at> tcd.ie, bug-gnu-emacs <at> gnu.org:
bug#62068; Package emacs. (Thu, 09 Mar 2023 08:17:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Augusto Stoffel <arstoffel <at> gmail.com>:
New bug report received and forwarded. Copy sent to contovob <at> tcd.ie, bug-gnu-emacs <at> gnu.org. (Thu, 09 Mar 2023 08:17:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Augusto Stoffel <arstoffel <at> gmail.com>
To: bug-gnu-emacs <at> gnu.org
Subject: 29.0.60; map-elt and map-insert for nested structures
Date: Thu, 09 Mar 2023 09:16:30 +0100
I would like to suggest the following two functions to deal with nested
maps.  Let me know if you would like to see a patch.

--8<---------------cut here---------------start------------->8---
(defun map-elt-in (map keys &optional default)
  "Look up a nested sequence of KEYS in MAP and return its associated value.
KEYS is any sequence type supported by `seq'.  If a key is not
found in any intermediate step, return DEFAULT, which defaults to
nil."
  (catch 'map--break
    (seq-reduce (lambda (m k)
                  (let ((v (map-elt m k 'map--default)))
                    (if (eq v 'map--default)
                        (throw 'map--break default)
                      v)))
                keys
                map)))
--8<---------------cut here---------------end--------------->8---

Examples:

(map-elt-in '(x (y (z 1))) '(x y))
=> (z 1)
(map-elt-in '(x (y (z 1))) '(x y z))
=> 1
(map-elt-in '(x (y (z 1))) '(x y zz))
=> nil
(map-elt-in '(x (y (z 1))) '(x yy zz) 99)
=> 99

--8<---------------cut here---------------start------------->8---
(defun map-insert-in (map keys value &optional default-type)
  "Return a new map like MAP except that it the nested KEYS with VALUE.
This does not modify MAP.  KEYS is any sequence type supported by
`seq'.  If intermediate values are missing, they are created with
DEFAULT-TYPE."
  (when (seq-empty-p keys)
    (error "Keys sequence must not be empty."))
  (named-let recur ((map map) (keys keys))
    (let* ((k (seq-first keys))
           (ks (seq-rest keys))
           (new (if (seq-empty-p ks)
                   (map-insert map k value)
                 (map-insert map k (recur (map-elt map k) ks)))))
      (if (and (not map) default-type) (map-into new default-type) new))))
--8<---------------cut here---------------end--------------->8---

Examples:
(map-insert-in nil '(x y z) 1)
=> ((x (y (z . 1))))

(map-insert-in nil '(x y z) 1 'plist)
=> (x (y (z 1)))

(map-insert-in '(x 2 y (z 3)) '(y a b) 1 'plist)
=> (y (a (b 1) z 3) x 2 y (z 3))
;; Looks funny, but see bug#62067




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62068; Package emacs. (Fri, 10 Mar 2023 01:19:01 GMT) Full text and rfc822 format available.

Message #8 received at 62068 <at> debbugs.gnu.org (full text, mbox):

From: Michael Heerdegen <michael_heerdegen <at> web.de>
To: Augusto Stoffel <arstoffel <at> gmail.com>
Cc: "Basil L. Contovounesios" <contovob <at> tcd.ie>, 62068 <at> debbugs.gnu.org
Subject: Re: bug#62068: 29.0.60; map-elt and map-insert for nested structures
Date: Fri, 10 Mar 2023 02:18:35 +0100
Augusto Stoffel <arstoffel <at> gmail.com> writes:

> I would like to suggest the following two functions to deal with nested
> maps.  Let me know if you would like to see a patch.
>
> (defun map-elt-in (map keys &optional default)
>   "Look up a nested sequence of KEYS in MAP and return its associated value.
> KEYS is any sequence type supported by `seq'.  If a key is not
> found in any intermediate step, return DEFAULT, which defaults to
> nil."
>   (catch 'map--break
>     (seq-reduce (lambda (m k)
>                   (let ((v (map-elt m k 'map--default)))
>                     (if (eq v 'map--default)
>                         (throw 'map--break default)
>                       v)))
>                 keys
>                 map)))

Isn't this more or less the same as `map-nested-elt'?

Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62068; Package emacs. (Fri, 10 Mar 2023 07:10:01 GMT) Full text and rfc822 format available.

Message #11 received at 62068 <at> debbugs.gnu.org (full text, mbox):

From: Augusto Stoffel <arstoffel <at> gmail.com>
To: Michael Heerdegen <michael_heerdegen <at> web.de>
Cc: "Basil L. Contovounesios" <contovob <at> tcd.ie>, 62068 <at> debbugs.gnu.org
Subject: Re: bug#62068: 29.0.60; map-elt and map-insert for nested structures
Date: Fri, 10 Mar 2023 08:09:29 +0100
On Fri, 10 Mar 2023 at 02:18, Michael Heerdegen wrote:

> Augusto Stoffel <arstoffel <at> gmail.com> writes:
>
>> I would like to suggest the following two functions to deal with nested
>> maps.  Let me know if you would like to see a patch.
>>
>> (defun map-elt-in (map keys &optional default)
>>   "Look up a nested sequence of KEYS in MAP and return its associated value.
>> KEYS is any sequence type supported by `seq'.  If a key is not
>> found in any intermediate step, return DEFAULT, which defaults to
>> nil."
>>   (catch 'map--break
>>     (seq-reduce (lambda (m k)
>>                   (let ((v (map-elt m k 'map--default)))
>>                     (if (eq v 'map--default)
>>                         (throw 'map--break default)
>>                       v)))
>>                 keys
>>                 map)))
>
> Isn't this more or less the same as `map-nested-elt'?

How did I miss that?  In any case the more interesting bit is the other
function, which should then be renamed to `map-nested-insert'.

Now, `map-nested-elt' has an inconsistency regarding the DEFAULT
argument which needs to be fixed.

(map-nested-elt '(a nil) '(a) 1)
1
(map-nested-elt '((a . nil)) '(a) 1)
1
etc.

While in the other hand:
(map-elt '(a nil) 'a 1)
nil
(map-elt '((a . nil)) 'a 1)
nil
etc.

Also inconsistent with the rest of Emacs:
(let ((m (make-hash-table)))
  (puthash 'a nil m)
  (gethash 'a m 1))
nil
(alist-get 'a '((a . nil)) 1)
nil





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62068; Package emacs. (Sat, 11 Mar 2023 03:23:01 GMT) Full text and rfc822 format available.

Message #14 received at 62068 <at> debbugs.gnu.org (full text, mbox):

From: Michael Heerdegen <michael_heerdegen <at> web.de>
To: Augusto Stoffel <arstoffel <at> gmail.com>
Cc: "Basil L. Contovounesios" <contovob <at> tcd.ie>,
 Nicolas Petton <nicolas <at> petton.fr>, 62068 <at> debbugs.gnu.org
Subject: Re: bug#62068: 29.0.60; map-elt and map-insert for nested structures
Date: Sat, 11 Mar 2023 04:22:15 +0100
Augusto Stoffel <arstoffel <at> gmail.com> writes:

> How did I miss that?  In any case the more interesting bit is the other
> function, which should then be renamed to `map-nested-insert'.

Is that something one will really need often (honest question, I'm
really curious)?  If yes, I wonder if we should make it work as a
generalized variable.

> Now, `map-nested-elt' has an inconsistency regarding the DEFAULT
> argument which needs to be fixed.
>
> (map-nested-elt '(a nil) '(a) 1)
> 1
> (map-nested-elt '((a . nil)) '(a) 1)
> 1
> etc.
>
> While in the other hand:
> (map-elt '(a nil) 'a 1)
> nil
> (map-elt '((a . nil)) 'a 1)
> nil
> etc.
> [...]

That's a good point indeed.  However, `map-nested-elt' exists since the
beginning of the library in 2015, so it could be that existing code
relies on the behavior (maybe that's why you wanted to add a new
function?).  But it's a terrible inconsistency.

CC'ing also Nicolas.

Should we maybe just add Augusto's version and deprecate the existing
function?


Thanks,

Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62068; Package emacs. (Sat, 11 Mar 2023 07:52:02 GMT) Full text and rfc822 format available.

Message #17 received at 62068 <at> debbugs.gnu.org (full text, mbox):

From: Augusto Stoffel <arstoffel <at> gmail.com>
To: Michael Heerdegen <michael_heerdegen <at> web.de>
Cc: "Basil L. Contovounesios" <contovob <at> tcd.ie>,
 Nicolas Petton <nicolas <at> petton.fr>, 62068 <at> debbugs.gnu.org
Subject: Re: bug#62068: 29.0.60; map-elt and map-insert for nested structures
Date: Sat, 11 Mar 2023 08:51:33 +0100
On Sat, 11 Mar 2023 at 04:22, Michael Heerdegen wrote:

> Augusto Stoffel <arstoffel <at> gmail.com> writes:
>
>> How did I miss that?  In any case the more interesting bit is the other
>> function, which should then be renamed to `map-nested-insert'.
>
> Is that something one will really need often (honest question, I'm
> really curious)?

I think it's very useful when you need it :-).  Actually, I wouldn't use
map-elt in any code, because I always know what type I'm dealing with.
I would just turn to this library for special maneuvers that the basic
API doesn't offer.

>  If yes, I wonder if we should make it work as a
> generalized variable.

Maybe, but that's a separate story.  First and most importantly, in my
opinion, the library should work right on values (as opposed to places).

>> Now, `map-nested-elt' has an inconsistency regarding the DEFAULT
>> argument which needs to be fixed.
>>
>> (map-nested-elt '(a nil) '(a) 1)
>> 1
>> (map-nested-elt '((a . nil)) '(a) 1)
>> 1
>> etc.
>>
>> While in the other hand:
>> (map-elt '(a nil) 'a 1)
>> nil
>> (map-elt '((a . nil)) 'a 1)
>> nil
>> etc.
>> [...]
>
> That's a good point indeed.  However, `map-nested-elt' exists since the
> beginning of the library in 2015, so it could be that existing code
> relies on the behavior (maybe that's why you wanted to add a new
> function?).

(No, the reason was just pure oversight.  Maybe "elt" is a weird word?
Why isn't it `map-get' and `map-nested-get'?)

>  But it's a terrible inconsistency.

There are more consistency issues in this library, see bug#62067 and
bug#62117.  Emacs has its quirks and one of the selling points of map.el
is to be a more consistent layer on top of the basic APIs, so I'd say
this need to be fixed.




This bug report was last modified 1 year and 44 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.