Use of :method option in defgeneric
Asked Answered
C

2

7

I notice, upon reading Keene's book, that defgeneric has a :method option, which seems like it allows you to specify a method in the generic definition itself. Most documentation I've seen has all of the applicable methods defined in separate defmethods. The hyperspec, with its usual clarity, lists :method as an option for defgeneric, but does not say what it means.

Does the :method option present a default, or at least, document what you expect the most common use case will be, or does it have additional semantics? As a style point, if you expect to define only one method, does it make more sense to define it in the defgeneric form (if you can, indeed, do that), or separately in a defmethod? Or does it not make sense to make a generic function in this case at all, and instead use a regular defun?

Chilly answered 15/4, 2015 at 0:26 Comment(0)
A
9

The hyperspec, with its usual clarity, lists :method as an option for defgeneric, but does not say what it means.

Actually, the HyperSpec entry for defgeneric, with its usual clarity, says exactly what it means. It says the syntax for defgeneric is:

defgeneric function-name gf-lambda-list [[option | {method-description}*]]

and then says that the syntax for method-description is:

method-description::= (:method method-qualifier* specialized-lambda-list [[declaration* | documentation]] form*)

And then it describes method-combination:

Each method-description defines a method on the generic function. The lambda list of each method must be congruent with the lambda list specified by the gf-lambda-list option. If no method descriptions are specified and a generic function of the same name does not already exist, a generic function with no methods is created.

So the :method forms are for defining methods on the generic function, just like defmethod forms.

(I will grant that it doesn't really say anything about why you'd prefer defgeneric plus :method as opposed to defmethod. Remember that the Common in Common Lisp means that the language is an attempt to unify lots of existing Lisp implementations. Maybe some supported :method and others supported defmethod, and this was the easiest way to provide a unified interface.)

That is, the following would have the same effect:

(defgeneric to-list (object))

(defmethod to-list ((object t))
  (list object))

(defmethod to-list ((object list))
  object)

(defgeneric to-list (object)
  (:method ((object t)) 
    (list object))
  (:method ((object list))
    object))

Sometimes it can be convenient to define some of the methods along with the defgeneric form. It's more a matter of style, and this gets into the other parts of your question.

Does the :method option present a default, or at least, document what you expect the most common use case will be, or does it have additional semantics?

It can be a sort of default, if you define a method without type specifiers, or with type specifiers that apply to every object (e.g., t).

As a style point, if you expect to define only one method, does it make more sense to define it in the defgeneric form (if you can, indeed, do that), or separately in a defmethod? Or does it not make sense to make a generic function in this case at all, and instead use a regular defun?

I think it depends on why you expect to define only one method. If it's because you're just defining a default, but expect other users to implement methods on it, then putting the methods along with the defmethod might be convenient if anyone needs to find the source. If you expect that there's only one thing to do, then a normal function might make more sense. I think these decisions just come down to style choices.

It's also worth noting that there are other forms that can define methods on a generic function (and other forms that can produce generic functions, too). In the HyperSpec, using the up arrows to go to higher sections will usually bring you to more prose. In this case, 7.6.1 Introduction to Generic Functions is useful:

Some operators define methods for a generic function. These operators will be referred to as method-defining operators; their associated forms are called method-defining forms. The standardized method-defining operators are listed in the next figure.

defgeneric        defmethod  defclass  
define-condition  defstruct
Acuff answered 15/4, 2015 at 2:59 Comment(3)
CLOS was mostly based on Flavors/New Flavors and LOOPS/CommonLOOPS. Many methods can be long and usually it is not liked to place several of them inside one long form. Also one method alone makes redefining kind of easier/faster...Gibran
Thanks. Perhaps the hyperspec is meant for people with better eyes than mine. (I can't believe I let an "it's" in there when I mean "its".)Chilly
@Chilly There are actually some other forms that introduce methods on generic functions (and in some cases introduce the generic functions, too). Some of the prose parts of the hyperspec discuss this; I've updated my answer with a paragraph at the end.Acuff
G
2

It's up to personal preference and what how the system would be organized in source. Either

  • simple generic function: a bunch of DEFMETHODS

  • complex generic function: a DEFGENERIC and a bunch of DEFMETHODS

  • generic function: a DEFGENERIC and a bunch of methods inside

Most Lisp OO-systems before CLOS used the single method definition form. Code could get too long in one form otherwise, generic functions mostly did not exist, ...

With class-oriented single-dispatch systems it could have made sense to organize methods in a class definition. With the introduction of generic functions and multiple dispatch it made sense to organize them under a generic function definition.

Gibran answered 15/4, 2015 at 13:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.