In this answer, the user gave a very clear example on how classes and methods work together.
I will reprint the example here:
(defclass human () ())
(defclass dog () ())
(defmethod greet ((thing human))
(print "Hi human!"))
(defmethod greet ((thing dog))
(print "Wolf-wolf dog!"))
(defparameter Anna (make-instance 'human))
(defparameter Rex (make-instance 'dog))
(greet Anna) ;; => "Hi human"
(greet Rex) ;; => "Wolf-wolf dog!"
My question is, using the same example:
- What value would creating a generic functions add?
- Why are generic functions useful? Are they like instances in other OO languages that provide structure?
It seems that generic functions are created in the background implicitly (not 100% sure). I notice that when I play with this example, if I create a method that has a different param structure than the first instance of the method, I get a generic function error
.
I like to declare the generic function explicitly because it is possible to add documentation and declarations that are relative to the generic function (optimize for speed/space/debug), and other details such as method combination (a.k.a. when you have multiple methods applicable for a given call, this defines which are executed and in which order). Here for example I can define
talk
as having aprogn
method combination (all methods are executed as-if encapsulated in aprogn
form):This is a bit contrived example, but here we go:
Defining a class that inherits from both means that a call to
talk
for an instance of the class can execute two methods (sorted in a somewhat topological order called the Method Resolution Order). So with this method combination all the methods are executed:But, I would say that being able to document the generic function is by itself a good enough reason to declare it with
defgeneric
.If you define
talk
as a generic function you allow any class to participate in code that callstalk
(e.g. a library), this is a way to allow extensions without having to close the set of possible values, unlike using something liketypecase
in a function where you can only list a predefined set of cases.For example the standard functions
print-object
is called at various times in your Lisp implementation (in the inspector, the REPL, the debugger), if you want you can implement a method for your custom types without having to hack the internals of your environment.Generic functions are, unlike in other OO languages, not tied to a single class or instance. They can be specialized1 on more than one argument, which means none of them "owns" the generic function.
1. specialized is defined as follows:
The idea behind this is that methods can be more or less specific: a method of two arguments
a
andb
that specializes both on(a number)
and(b string)
is more specific than another one that specializes only on(b vector)
, and methods are actually sorted from the most specific to the least specific ones (resp. from the least to the most) when combining them. You can even specialize a function on(a (eql 10))
to cover only the specific case of an argumenta
beingeql
to 10.