unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#29786: 27.0.50; About the argument list of methods
@ 2017-12-20 12:38 Michael Heerdegen
  2017-12-27  3:01 ` Stefan Monnier
  0 siblings, 1 reply; 4+ messages in thread
From: Michael Heerdegen @ 2017-12-20 12:38 UTC (permalink / raw)
  To: 29786


Hello,

(1) In (info "(elisp) Generic Functions"), there is this paragraph:

 -- Macro: cl-defmethod name [qualifier] arguments &rest [docstring]
          body
     [...]
     The ARGUMENTS list, which must be identical in all the methods that
     implement a generic function, and must match the argument list of
     that function, provides argument specializers of the form ‘(ARG
     SPEC)’, where ARG is the argument name as specified in the
     ‘cl-defgeneric’ call, and SPEC is one of the following specializer
     forms: [...]

It's not clear to me what the sentence saying the argument lists must
all be identical tries to say.  Surely they can't all be identical when
they need to specify different specializers?  Is there anything to say
at all, apart from the necessity to match the argument list of the
generic function mentioned in the next sentence?  Do I have to use the
same argument names as specified in the generic method?  That would be
suboptimal for my use case:

(2)  I want to implement a method of `seq-mapn' (see seq.el) for
streams.  It would be good if the following worked as expected:

#+begin_src emacs-lisp
(cl-defmethod seq-mapn (function (stream stream) &rest streams)
  "Map FUNCTION over the STREAMS.

Example: this prints the first ten Fibonacci numbers:

  (letrec ((fibs (stream-cons
                  1
                  (stream-cons
                   1
                   (seq-mapn #'+ fibs (stream-rest fibs))))))
    (seq-do #'print (seq-take fibs 10)))

\(fn FUNCTION STREAMS...)"
  (if (not (seq-every-p #'streamp streams))
      (cl-call-next-method)
    (cl-labels ((helper (f streams)
                        (stream-make
                         (unless (seq-some #'stream-empty-p streams)
                           (cons (apply f (mapcar #'stream-first streams))
                                 (helper f (mapcar #'stream-rest streams)))))))
      (helper function (cons stream streams)))))
#+end_src

Then C-h f seq-mapn prints the argument list of that method as

  (arg2 (arg3 stream) &rest rest)

Debugging suggested that "STREAMS..." is treated as a symbol name by the
code and rejected because it contains dots.

But even when I replace the signature specifying line at the end of the
docstring with "\(fn FUNCTION &rest STREAMS)", I get

  (arg0 (arg1 stream) &rest streams)

instead of what I have specified.  This only happens if I load the
byte-compiled code, however.

I think the documentation tries to say that I have to use exactly the
same argument names as in the generic method:

#+begin_src emacs-lisp
(cl-defmethod seq-mapn (function (sequence stream) &rest sequences)
  "Map FUNCTION over the STREAMS.

Example: this prints the first ten Fibonacci numbers:

  (letrec ((fibs (stream-cons
                  1
                  (stream-cons
                   1
                   (seq-mapn #'+ fibs (stream-rest fibs))))))
    (seq-do #'print (seq-take fibs 10)))"
  (if (not (seq-every-p #'streamp sequences))
      (cl-call-next-method)
    (cl-labels ((helper (f streams)
                        (stream-make
                         (unless (seq-some #'stream-empty-p streams)
                           (cons (apply f (mapcar #'stream-first streams))
                                 (helper f (mapcar #'stream-rest streams)))))))
      (helper function (cons sequence sequences)))))
#+end_src

That gives me for C-h f:

Implementations:

(sequence (arg1 stream) &rest sequences) in `~/software/elpa/packages/stream/stream.el'.

That's a total mess now: the first argument FUNCTION is called
"sequence", the second arg "arg1", and the third &rest argument
"sequences", which is not what I want because these must all be streams
(as tested in the method body), so this results in the most confusing
generated documentation of all.


TIA,

Michael.


In GNU Emacs 27.0.50 (build 24, x86_64-pc-linux-gnu, GTK+ Version 3.22.24)
 of 2017-12-14 built on drachen
Repository revision: 269fa5482d0761e612734b87982d7a708330bd37
Windowing system distributor 'The X.Org Foundation', version 11.0.11905000
System Description: Debian GNU/Linux testing (buster)






^ permalink raw reply	[flat|nested] 4+ messages in thread

* bug#29786: 27.0.50; About the argument list of methods
  2017-12-20 12:38 bug#29786: 27.0.50; About the argument list of methods Michael Heerdegen
@ 2017-12-27  3:01 ` Stefan Monnier
  2017-12-27 12:29   ` Michael Heerdegen
  0 siblings, 1 reply; 4+ messages in thread
From: Stefan Monnier @ 2017-12-27  3:01 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 29786

> It's not clear to me what the sentence saying the argument lists must
> all be identical tries to say.  Surely they can't all be identical when
> they need to specify different specializers?

All that matters is that they should all accept the same number of arguments.

> (cl-defmethod seq-mapn (function (stream stream) &rest streams)
>   "Map FUNCTION over the STREAMS.
>
> Example: this prints the first ten Fibonacci numbers:
>
>   (letrec ((fibs (stream-cons
>                   1
>                   (stream-cons
>                    1
>                    (seq-mapn #'+ fibs (stream-rest fibs))))))
>     (seq-do #'print (seq-take fibs 10)))
>
> \(fn FUNCTION STREAMS...)"

I think this "\(fn FUNCTION STREAMS...)" thingy doesn't make sense for
`cl-defmethod`: it only makes sense for `cl-defgeneric`.

> (cl-defmethod seq-mapn (function (sequence stream) &rest sequences)
>   "Map FUNCTION over the STREAMS.
[...]
>     (seq-do #'print (seq-take fibs 10)))"
[...]
> That gives me for C-h f:
>
> Implementations:
>
> (sequence (arg1 stream) &rest sequences) in `~/software/elpa/packages/stream/stream.el'.

Oh, indeed, we have a bug in cl--generic-lambda:
We create a (cl-function (lambda (function stream &rest streams) ...)),
then macroexpand it, then retro-fit an additional `cnm` argument (the
implicit argument that holds the "next method", used by
cl-call-next-method).  But when we retro-fit this `cnm` argument, we're
not careful to update the potential (fn FOO) stuff added at the end of
the docstring.

Not sure how best to fix it,


        Stefan "who curses the idiot who came up with this gross (fn FOO) hack"





^ permalink raw reply	[flat|nested] 4+ messages in thread

* bug#29786: 27.0.50; About the argument list of methods
  2017-12-27  3:01 ` Stefan Monnier
@ 2017-12-27 12:29   ` Michael Heerdegen
  2017-12-27 14:52     ` Stefan Monnier
  0 siblings, 1 reply; 4+ messages in thread
From: Michael Heerdegen @ 2017-12-27 12:29 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 29786

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> > (cl-defmethod seq-mapn (function (stream stream) &rest streams)
> >   "Map FUNCTION over the STREAMS.
> >
> > Example: this prints the first ten Fibonacci numbers:
> >
> >   (letrec ((fibs (stream-cons
> >                   1
> >                   (stream-cons
> >                    1
> >                    (seq-mapn #'+ fibs (stream-rest fibs))))))
> >     (seq-do #'print (seq-take fibs 10)))
> >
> > \(fn FUNCTION STREAMS...)"
>
> I think this "\(fn FUNCTION STREAMS...)" thingy doesn't make sense for
> `cl-defmethod`: it only makes sense for `cl-defgeneric`.

But it does make sense in this example, no?


Thanks,

Michael.





^ permalink raw reply	[flat|nested] 4+ messages in thread

* bug#29786: 27.0.50; About the argument list of methods
  2017-12-27 12:29   ` Michael Heerdegen
@ 2017-12-27 14:52     ` Stefan Monnier
  0 siblings, 0 replies; 4+ messages in thread
From: Stefan Monnier @ 2017-12-27 14:52 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 29786

>> > (cl-defmethod seq-mapn (function (stream stream) &rest streams)
[...]
>> > \(fn FUNCTION STREAMS...)"
>> I think this "\(fn FUNCTION STREAMS...)" thingy doesn't make sense for
>> `cl-defmethod`: it only makes sense for `cl-defgeneric`.
> But it does make sense in this example, no?

Not really, no: in the docstring of `seq-mapn` what we want to show to
the user about the above method is when it applies, i.e. its
"specializers".  We could try to make it say that the specializer is
"all args after `function` are of type `stream`", but there's no
standard format to express that.  We could invent one, like

    (seq-mapn FUNCTION &rest (STREAMS (list stream)))
or
    (seq-mapn FUNCTION (STREAM stream) ...)

but it seems like more trouble than it's worth.


        Stefan





^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-12-27 14:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-20 12:38 bug#29786: 27.0.50; About the argument list of methods Michael Heerdegen
2017-12-27  3:01 ` Stefan Monnier
2017-12-27 12:29   ` Michael Heerdegen
2017-12-27 14:52     ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).