bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#22336: 25.0.50; cl-generic.el features are not documented in ELisp m


From: Dmitry Gutov
Subject: bug#22336: 25.0.50; cl-generic.el features are not documented in ELisp manual
Date: Sat, 23 Jan 2016 20:02:36 +0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:44.0) Gecko/20100101 Thunderbird/44.0

On 01/23/2016 03:51 PM, Eli Zaretskii wrote:

   (defmacro cl-defgeneric (name args &rest options-and-methods)
     "Create a generic function NAME.
   DOC-STRING is the base documentation for this class.  A generic
   function has no body, as its purpose is to decide which method body
   is appropriate to use.  Specific methods are defined with `cl-defmethod'.
   With this implementation the ARGS are currently ignored.
   OPTIONS-AND-METHODS currently understands:
   - (:documentation DOCSTRING)
   - (declare DECLARATIONS)
   - (:argument-precedence-order &rest ARGS)
   - (:method [QUALIFIERS...] ARGS &rest BODY)
   BODY, if present, is used as the body of a default method.

   \(fn NAME ARGS [DOC-STRING] [OPTIONS-AND-METHODS...] &rest BODY)"

It says a generic function has no body, but the usage info does
mention body, and the last part of the doc string says BODY if present
is used as the default method.  Or is that the body of :method?

BODY is "&rest BODY" from the advertised arglist you can see using `M-x describe-function'. It's also visible above in the last line of the docstring. The phrase "generic function has no body" is trying to say, apparently, that a generic function is not really a function (but more like a multi-dimensional hash-table), and the default method, which you _can_ provide inside the cl-defgeneric form, is the default value in that table.

Usage example:

(cl-defgeneric foo (a)
  10)

(cl-defmethod foo ((a integer))
  (* 20 a))

(foo 'a)
10

(foo 4)
80

Anyway, specific methods can evidently be defined by cl-defgeneric as
well, whereas the doc string says they should be defined by
cl-defmethod.  The semantics of :method is never described at all (and
I saw no examples of its usage to inspire me, AFAIR).

Is the can/should distinction a problem? Yes, when in doubt, cl-defmethod should be used, but one can define them inline as well.

I think the semantics are easy to guess, but I probably glanced at CL's documentation as well at some point:

(cl-defgeneric foo (a)
  (:method ((s string)) "stringy!")
  (:method ((a array)) :four)
  10)

(foo "s")
"stringy!"

(foo [1 2 3])
:four

TBH, I haven't used this even once in practice.

"_The_ dispatch argument", in singular means only one such argument is
possible, which is of course false.

Indeed. There's a case to be made for discouraging multiple-argument dispatch ("implemented rather naively"), but the docstring should be corrected anyway.

The &context dispatch has a
slightly different syntax, but it isn't mentioned here at all, which
makes the description of (VAR TYPE) incorrect in that case.

Also true.

Some omissions are very hard to restore.  The most striking example is
TYPE, about which the doc string says nothing at all, and the
commentary says just "plain old types".  How could you arrive at the
long list that's now in the manual, let alone the type hierarchy that
goes with it, except by reading the sources?

No idea. I was only vaguely aware, if that, of being able to dispatch on atomic types, before reading the manual. Thanks for that.

But the docstrings don't mention any of the possible values of TYPE (except (eql ...)), not just "plain old" ones. So I'm not clear on what exactly you consider an omission here. cl-defmethod docstring should probably enumerate the possible types (aside from the mentioned ones, TYPE can be (head ...) or a name of cl-struct, like the commentary says).

As another example, the ":extra STRING" feature is mentioned, but
without any details; I couldn't understand how to use it in practice
(it is not used in the tests, either).

I don't know either.

And I don't recommend believing the commentary too much, either.
E.g., what it says about &context in several places is contradictory:

   ;;   E.g. (foo &context (major-mode (eql c-mode))) is an arglist specifying
   ;;   that this method will only be applicable when `major-mode' has value
   ;;   `c-mode'.

and then:

   ;; - then define a context-rewriter so you can write
   ;;   "&context (major-mode c-mode)" rather than
   ;;   "&context (major-mode (derived-mode c-mode))".

Apparently, you can use both forms:

(cl-defmethod bar (&context (major-mode emacs-lisp-mode))
  'elisp)

(cl-defmethod bar (&context (major-mode (eql c-mode)))
  'c)

and even

   ;; TODO:
   ;;
   ;; - A way to dispatch on the context (e.g. the major-mode, some global
   ;;   variable, you name it).

Yup, this should just be removed.

which makes you think it isn't even implemented...  Also, there's
something about derived-mode there, but it's so contrived and devoid
of examples, that I didn't even put that in the manual.

Good call.

There were others I was only too happy to forget.

Thanks. I think fixing just the things you've mentioned will already be a step forward.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]