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 defmethod
s. 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
?
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