GNU bug report logs - #38252
27.0.50; Gnus server definitions and generic function specializers

Previous Next

Package: emacs;

Reported by: Eric Abrahamsen <eric <at> ericabrahamsen.net>

Date: Sun, 17 Nov 2019 22:32:02 UTC

Severity: normal

Found in version 27.0.50

To reply to this bug, email your comments to 38252 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 larsi <at> gnus.org, monnier <at> iro.umontreal.ca, bug-gnu-emacs <at> gnu.org:
bug#38252; Package emacs. (Sun, 17 Nov 2019 22:32:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Eric Abrahamsen <eric <at> ericabrahamsen.net>:
New bug report received and forwarded. Copy sent to larsi <at> gnus.org, monnier <at> iro.umontreal.ca, bug-gnu-emacs <at> gnu.org. (Sun, 17 Nov 2019 22:32:02 GMT) Full text and rfc822 format available.

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

From: Eric Abrahamsen <eric <at> ericabrahamsen.net>
To: bug-gnu-emacs <at> gnu.org
Subject: 27.0.50; Gnus server definitions and generic function specializers
Date: Sun, 17 Nov 2019 14:31:13 -0800
I'm working on changing Gnus servers into structs, and replacing the
nnoo.el architecture with generic functions, and while I think I've got
a workable roadmap I'm running into some practical confusions. Stefan
I'm ccing you directly because I suspect you're the only one who knows
the answers to my questions :)

The approach is this: Change the server interface functions in
gnus-int.el into generic functions. Provide a generalizer that
recognizes current Gnus servers, and dispatches to the current function
definitions (using `gnus-get-function' and all that). Gradually change
the in-tree backends to be defined with cl-defstruct, and use normal
dispatching-on-struct for those. Eventually the legacy generalizer would
be left in place just to deal with old-style out-of-tree backends.

As an example, here's what `gnus-request-list' currently looks like:

--8<---------------cut here---------------start------------->8---
gnus-int.el:
(defun gnus-request-list (gnus-command-method)
  (funcall (gnus-get-function gnus-command-method 'request-list)
	   (nth 1 gnus-command-method)))

nnimap.el:
(deffoo nnimap-request-list (&optional server)
 <get IMAP group list>)
--8<---------------cut here---------------end--------------->8---

Afterward it would look like this:

--8<---------------cut here---------------start------------->8---
gnus-int.el:
(cl-defgeneric gnus-request-list (server)
  "Docs and stuff.")

(cl-defmethod gnus-request-list ((server gnus-server-legacy))
  (funcall (gnus-get-function server 'request-list)
	   (nth 1 server)))

nnimap.el:
(cl-defmethod gnus-request-list ((server gnus-server-imap))
  <get IMAP group list>)
--8<---------------cut here---------------end--------------->8---

The nnimap version will dispatch on the `gnus-server-imap' defstruct,
that happens automatically. What I need is to be able to write a
generalizer/specializer that will recognize a legacy server (if calling
it "legacy" is annoying I can find something else) and dispatch on it.
The docstring of `cl-generic-define-generalizer' is gnomic, though I
found some better information in the docstring of
`cl-generic-generalizers', and looked at some of the existing
generalizer definitions.

Here's what I've worked up so far:

--8<---------------cut here---------------start------------->8---
(cl-generic-define-generalizer gnus-legacy-server-generalizer
  90 (lambda (name &rest _) `(???)
  (lambda (tag &rest _) (when (eq (car-safe tag) 'gnus-legacy-server)
			  (list tag))))

(cl-defmethod cl-generic-generalizers :extra "gnus-legacy-server" (thing)
  "Dispatch on old-style Gnus server definitions."
  (when wut?
    (list gnus-legacy-server-generalizer)))
--8<---------------cut here---------------end--------------->8---

What I'm trying to do is fairly simple: if the argument is a list, and
the head of the list is a symbol that can be assoc'd into
`nnoo-definition-alist', and the second element is a string, then it's a
gnus-legacy-server. I just don't know where that test is supposed to go,
or why.

I understand this will probably be inefficient and ugly, but I hope that
before too long it would be a rare case that the generalizer is checked
at all.

Thanks,
Eric




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#38252; Package emacs. (Mon, 18 Nov 2019 02:04:01 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eric Abrahamsen <eric <at> ericabrahamsen.net>
Cc: larsi <at> gnus.org, 38252 <at> debbugs.gnu.org
Subject: Re: bug#38252: 27.0.50; Gnus server definitions and generic
 function specializers
Date: Sun, 17 Nov 2019 21:03:00 -0500
> I'm ccing you directly because I suspect you're the only one who knows
> the answers to my questions :)

I doubt it, there's a lot of people around here more familiar with
CLOS-style programming than I.

> --8<---------------cut here---------------start------------->8---
> gnus-int.el:
> (cl-defgeneric gnus-request-list (server)
>   "Docs and stuff.")
>
> (cl-defmethod gnus-request-list ((server gnus-server-legacy))
>   (funcall (gnus-get-function server 'request-list)
> 	   (nth 1 server)))

Why not just:

    (cl-defmethod gnus-request-list (server)
      (funcall (gnus-get-function server 'request-list)
    	       (nth 1 server)))

which means "use it as a fallback".  The downside is that it will be
used for non-legacy servers if there is no specific implementation for
that server, but presumably you can detect it and signal an appropriate
error somewhere inside gnus-get-function.

> What I'm trying to do is fairly simple: if the argument is a list, and
> the head of the list is a symbol that can be assoc'd into
> `nnoo-definition-alist', and the second element is a string, then it's a
> gnus-legacy-server.

Why not just use a `cons` specializer?

IIUC all the non-legacy servers will use structs, so you don't need to
use a specializer that's so specific that it has to check "if the
argument is a list, and the head of the list is a symbol that can be
assoc'd into `nnoo-definition-alist', and the second element is
a string".


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#38252; Package emacs. (Mon, 18 Nov 2019 03:19:02 GMT) Full text and rfc822 format available.

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

From: Eric Abrahamsen <eric <at> ericabrahamsen.net>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: larsi <at> gnus.org, 38252 <at> debbugs.gnu.org
Subject: Re: bug#38252: 27.0.50; Gnus server definitions and generic
 function specializers
Date: Sun, 17 Nov 2019 19:18:30 -0800
On 11/17/19 21:03 PM, Stefan Monnier wrote:
>> I'm ccing you directly because I suspect you're the only one who knows
>> the answers to my questions :)
>
> I doubt it, there's a lot of people around here more familiar with
> CLOS-style programming than I.
>
>> --8<---------------cut here---------------start------------->8---
>> gnus-int.el:
>> (cl-defgeneric gnus-request-list (server)
>>   "Docs and stuff.")
>>
>> (cl-defmethod gnus-request-list ((server gnus-server-legacy))
>>   (funcall (gnus-get-function server 'request-list)
>> 	   (nth 1 server)))
>
> Why not just:
>
>     (cl-defmethod gnus-request-list (server)
>       (funcall (gnus-get-function server 'request-list)
>     	       (nth 1 server)))
>
> which means "use it as a fallback".  The downside is that it will be
> used for non-legacy servers if there is no specific implementation for
> that server, but presumably you can detect it and signal an appropriate
> error somewhere inside gnus-get-function.
>
>> What I'm trying to do is fairly simple: if the argument is a list, and
>> the head of the list is a symbol that can be assoc'd into
>> `nnoo-definition-alist', and the second element is a string, then it's a
>> gnus-legacy-server.
>
> Why not just use a `cons` specializer?
>
> IIUC all the non-legacy servers will use structs, so you don't need to
> use a specializer that's so specific that it has to check "if the
> argument is a list, and the head of the list is a symbol that can be
> assoc'd into `nnoo-definition-alist', and the second element is
> a string".

Okay, perhaps I was overthinking this. I don't want to assume that the
fallback is an old-style server (we might want to use the fallback for
other purposes), but you're right that 'cons is pretty much sufficient.
If anyone feeds a cons value into a Gnus server interface function that
*isn't* a server definition, that falls into "serves you right"
territory.

But just so I don't feel like I wasted my afternoon: how *would* one
write the generalizer I'm talking about?

Thanks,
Eric




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#38252; Package emacs. (Mon, 18 Nov 2019 04:37:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eric Abrahamsen <eric <at> ericabrahamsen.net>
Cc: larsi <at> gnus.org, 38252 <at> debbugs.gnu.org
Subject: Re: bug#38252: 27.0.50; Gnus server definitions and generic
 function specializers
Date: Sun, 17 Nov 2019 23:36:09 -0500
> But just so I don't feel like I wasted my afternoon: how *would* one
> write the generalizer I'm talking about?

Ah, that part.
I guess It could look like (guaranteed 100% untested):

    (defvar gnus--legacy-server-tag (make-symbol "gnus-legacy-server"))
    (cl-generic-define-generalizer gnus-legacy-server-generalizer
      90 (lambda (varname &rest _)
           `(and (consp ,varname)
                 (symbolp (car ,varname))
                 (assq (car ,varname) nnoo-definition-alist)
                 (stringp (cadr ,varname))
                 gnus--legacy-server-tag))
      (lambda (tag &rest _)
        (when (eq tag gnus--legacy-server-tag) (list tag))))
    
    (cl-defmethod cl-generic-generalizers ((_ (eql gnus-legacy-server)))
      "Dispatch on old-style Gnus server definitions."
      (list gnus-legacy-server-generalizer))


-- Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#38252; Package emacs. (Mon, 18 Nov 2019 20:44:01 GMT) Full text and rfc822 format available.

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

From: Eric Abrahamsen <eric <at> ericabrahamsen.net>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: larsi <at> gnus.org, 38252 <at> debbugs.gnu.org
Subject: Re: bug#38252: 27.0.50; Gnus server definitions and generic
 function specializers
Date: Mon, 18 Nov 2019 12:43:37 -0800
On 11/17/19 23:36 PM, Stefan Monnier wrote:
>> But just so I don't feel like I wasted my afternoon: how *would* one
>> write the generalizer I'm talking about?
>
> Ah, that part.
> I guess It could look like (guaranteed 100% untested):
>
>     (defvar gnus--legacy-server-tag (make-symbol "gnus-legacy-server"))
>     (cl-generic-define-generalizer gnus-legacy-server-generalizer
>       90 (lambda (varname &rest _)
>            `(and (consp ,varname)
>                  (symbolp (car ,varname))
>                  (assq (car ,varname) nnoo-definition-alist)
>                  (stringp (cadr ,varname))
>                  gnus--legacy-server-tag))
>       (lambda (tag &rest _)
>         (when (eq tag gnus--legacy-server-tag) (list tag))))
>     
>     (cl-defmethod cl-generic-generalizers ((_ (eql gnus-legacy-server)))
>       "Dispatch on old-style Gnus server definitions."
>       (list gnus-legacy-server-generalizer))

That's perfect, thanks. I don't need tested code, I just needed to
understand the logic of which bit is responsible for what. I wonder if
it would be useful to have an example of this, either in the manual or
cl-generic.el code comments? 

There's still a lot of work to do before struct servers and cons servers
can coexist within Gnus, but it's nice to have this piece of the puzzle
solved.




This bug report was last modified 5 years and 213 days ago.

Previous Next


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