Subject: bug#78834: closed (Re: bug#78834: Sv: bug#78834: Feature request: make keymapp dereference symbol value slot)

From: [email-masked] (GNU bug Tracking System)
Date: Sat, 05 Jul 2025 07:26:04 +0000

Your bug report

#78834: Feature request: make keymapp dereference symbol value slot

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
78834: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=78834
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#78834: Sv: bug#78834: Feature request: make keymapp dereference symbol value slot
From: Eli Zaretskii <[email-masked]>
To: arthur miller <[email-masked]>
Cc: [email-masked], [email-masked]
Date: Sat, 05 Jul 2025 10:25:12 +0300
List-Id: <debbugs-submit.debbugs.gnu.org>

> Cc: "[email-masked]" <[email-masked]>
> From: arthur miller <[email-masked]>
> Date: Fri, 20 Jun 2025 00:15:29 +0000
> 
> > > I realized that and was doing something similar, admittedly less
> > > effeciently because I didn't know I can trust that all keymaps have the
> > > value slot set.
> >
> > Your mental model is a bit off.  Keymaps don't have a "value slot".
> > IOW, your old loop was looking for "symbols that are keymaps" (which is
> > only those whose function slot contains a keymap), but your new function
> > looks for "variables which *contain* a keymap".
> 
> Aha. Yes it was. I didn't get it that keymaps are *exclusively* symbols
> with a keymap in function slot. The doc says it, but since they are also
> stored in variables, I was a bit off there.
> 
> > Most useful/important keymaps are stored in variables, so yes that loop
> > will find almost all of the keymaps.  Not all, because some keymaps are
> > produced dynamically or are stored only elsewhere (such as inside one
> > of the sublists of `minor-mode-map-alist`).
> 
> Yes. I see. Some other defined in keymap.c are also not found.
> 
> The function that does the work for me, is processing each keymap
> recursively. Maps stored in those lists will hopefully also be defined
> elsewhere, otherwise, I will have to iterate those lists as special
> cases. I don't see otherwise how to ask for all the keymaps in the
> system. Hopefully it is only those alists defined in
> keymap.c. Dynamically generated ones are of the reach, unless they are
> stored in some parent keymap reachable from a variable in obarray.
> 
> > >> It's mostly used in very old code that uses the weird
> > >> `define-prefix-command` function, such as the code that sets up some of
> > >> the "core" keymaps like `ctl-x-5-prefix` `ESC-prefix` `ctl-x-4-prefix`,
> > >> `Control-X-prefix`.
> > > I was actually wondering why this was done, if it is just an
> > > optimization or if there is some other reason?  I am just curious, I
> > > don't really understand the idea behind.
> >
> > You'd have to ask Richard.  IIUC one of the benefit is that you can
> > refer (by name) to a keymap before it's defined.  E.g. you can do
> >
> >     (global-set-key [?\C-z] 'my-z-keymap)
> >
> > and then have `my-z-keymap` autoloaded from some library the first time
> > you hit `C-z`.  I can't remember the last time I've seen this used
> > successfully (I tried to use it a few times, but the keymap always
> > ended up being "accidentally" autoloaded much too eagerly).
> >
> > Maybe it was done simply because Richard thought of keymaps as kinds of
> > commands?
> 
> It seems so from the docs, but how does it work? Special code that
> handles keymaps when evaluation is done? I am not familiar with Emacs
> eval and how it handles commands yet.
> 
> > > It would be interesting to learn, if somebody knows and is willing to
> > > explain, since it is atypical to store value data in function slot.
> >
> > Indeed.
> >
> > >> It would break existing uses when the symbol has both
> > >> a `symbol-function` value and a `symbol-value` value.  We could
> > >> consider
> > > I saw the other functions using get_keymap, so I wasn't sure if they
> > > would complain or not. I have run Emacs today, the entire day, with that
> > > patch, I haven't noticed anything weird.
> >
> > I wouldn't expect otherwise.  The affected cases would be corner cases.
> >
> > > DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0,
> > >   (Lisp_Object object)
> > > {
> > >   if (NILP (object))
> > >     return Qnil;
> > >   if (CONSP (object) && EQ (XCAR (object), Qkeymap))
> > >     return object;
> > >
> > >   if (SYMBOLP (object))
> > >     {
> > >       Lisp_Object tem = indirect_function (object);
> > >       if (CONSP (tem) && EQ (XCAR (tem), Qkeymap))
> > >       return tem;
> > >
> > >       tem = find_symbol_value (object);
> > >       if (CONSP (tem) && EQ (XCAR (tem), Qkeymap))
> > >       return tem;
> > >     }
> > >
> > >   return Qnil;
> > > }
> >
> > That would be wrong.  Code can expect that if `keymapp` returns non-nil,
> > then you do have a keymap and you can use functions like
> > `set-keymap-parent`, `lookup-key`, `map-keymap`, ... on it.  So if you
> > change `keymapp` to return non-nil for some symbols, you need to adjust
> > the other operations as well.
> 
> Indeed, but they will get a keymap, won't they? Because the object
> stored in the symbol slot is a keymap. The only difference is from which
> slot the keymap is returned. But, I can imagine some code written to
> expect nil in some cases, now does not get nil, and perhaps does a wrong
> thing.
> 
> Anyway, that is a bit unfortunate, because I just found I still do have
> to check if the variable is bound before I take the symbol-function, so
> I have to type it like this:
> 
> (defun collect-keymaps ()
>   (cl-loop for s being the symbols
>            when
>            (or (keymapp s)
>                (and (boundp s) (keymapp (symbol-value s))))
>            collect s))
> 
> With the above function, I could type:
> 
> (defun collect-keymaps ()
>   (cl-loop for s being the symbols
>            when (keymapp s)    
>            collect s))
> 
> However, the second one with the patch finds one keymap less, 588 vs 587,
> in my Emacs :). I guess I'll better go with the old one anyway.

No further comments, so I'm closing this bug.

Subject: Feature request: make keymapp dereference symbol value slot
From: arthur miller <[email-masked]>
To: "[email-masked]" <[email-masked]>
Date: Wed, 18 Jun 2025 22:33:24 +0000
List-Id: <debbugs-submit.debbugs.gnu.org>

Currently keymapp returns nil, when passed a symbol if a keymap
object is only in a symbol's value slot, but not fbound:

(keymapp emacs-lisp-mode-map) => t
(keymapp 'emacs-lisp-mode-map) => nil

(boundp 'emacs-lisp-mode-map) => t
(fboundp 'emacs-lisp-mode-map) => nil

Keymapp uses internally get_keymap to check if an object is a keymap,
and get_keymap does not check value slot of symbols. However, the
comment above says:

"Check that OBJECT is a keymap (after dereferencing through any
   symbols).  If it is, return it."

Now, I don't know why is it the case, why the value slot is not
derefenced. I guess it is by design; after all this time this function
is in existence, that must be known. I don't understand the reason
though, by just looking at it at the moment, so I do wonder why is it
so?

Anyway, that leaves me in a bit awkward situation where I can ask a
question: (keymapp some-symbol) and get two different answers:

(keymapp 'emacs-lisp-mode-map) => nil
(keymapp 'vc-mode-map) => t

because one is fbound and the other is not. The background for this is
that I want to collect all loaded keymaps in the system:

(defun collect-keymaps ()
  (cl-loop for k being the symbol when (keymapp k) collect k))

But I don't get them all, since keymapp won't recognize those that are
not fbound. That makes the whole thing quite less effective, since I
have to additionally check if a symbol is bound and if its symbol value
is a keymap.

As a suggestion, the attached patch dereferences symbol value slots as
well. If it is not a wrong thing to do for some reason I am not aware
of, I would like to suggest it as a "fix" or a "feature request",
whichever is best describing the issue.