Lisp Corner Cases: Method Combinations

In the process of writing
Declt, I had
to deepen my knowledge of some Lisp corner cases, notably in the area of
introspection. As you know, Common Lisp has more than 2 namespaces (calling it
a “Lisp-2” is somewhat misleading). Sometimes, introspecting a potential
symbol definition in one namespace is trivial (compiler-macro-function
is
one example). The “functional” namespace is heterogeneous but you can still
make your way out of macros, regular or generic functions very easily.
Distinguishing constants, special variables and symbol macros in the
“variables” namespace is more complicated because there is no standard way to
access that information, but with the help of some vendor-specific machinery
(e.g. sb-int:info
), it’s still doable.
At some point, I tackled the case of method combinations, and to my greatest surprise, found out that introspecting a method combination by name is not simple. In fact, it’s not even doable. The reason is that method combinations don’t have a namespace proper. Let me explain why.
You define a new method combination of some NAME with
define-method-combination
, and you use it with the :method-combination
option to defgeneric
. But how do you introspect a NAME for a potential
method combination definition? Well, you can’t do exactly that. First, there
is no standard way to do so. Next, let’s look at what the MOP provides. One
would expect something along the lines of find-class
…
There is indeed something called find-method-combination
, but either I’m
missing something, or it is broken by design. The arguments to this function
are: a generic function meta-object, a method combination name and some method
combination options. So if this function is supposed to be the equivalent of
find-class
for method combinations, what are the 1st and 3rd arguments for?
In fact, this funjction is not supposed to do what its name suggests.
According to the AMOP, p.191, the purpose of this function is to “determine
the method combination object used by a generic function”. In practice however
(at least in SBCL), it’s not doing that either (see below), and anyway,
determining the method combination object used by a generic function is better
achieved by using the generic-function-method-combination
accessor.
So this protocol doesn’t seem to make any sense. In order to understand what
to make of all this, I looked at how SBCL handles method combinations (I don’t
know what other vendors do) and here is what I found. When you call
define-method-combination
for some NAME, SBCL creates a new method for
find-method-combination
, eql-specialized on that NAME. This method is
encapsulated in a closure containing the method combination’s definition,
ignores its first argument (the generic function meta-object; that’s why I
said that it’s not really doing what the AMOP says it does), recreates and
returns a new method combination object on the fly every time it is called.
This has several consequences. First, the notion of “method combination named NAME” doesn’t really make sense. Method combinations don’t have a proper namespace. Every time you create a new generic function, the method combination essentially becomes local to that function. Redefining a method combination has no effect on existing generic functions using a method combination of the same NAME. To put it differently, you can end up with several generic functions using different, yet equally named, method combinations.
In Declt, I’m now assuming that programmers behave and only define method
combinations once. Which brings us to the second consequence. With that
assumption in mind, the “proper” way to introspect a NAME for a method
combination definition (at least in SBCL) is to first look for the existence
of a find-method-combination
method eql-specialized on that NAME, and then
call it to retrieve the actual definition.
I haven’t thought about it a lot yet, but it would be interesting to
investigate the idea of cleaning this up a bit. I mean, establishing a real
global namespace for method combinations, creating an alternative
find-method-combination
protocol more along the lines of find-class
. And
then, it could also be interesting to investigate on the potential
applications of allowing method combination redefinition to affect live
generic functions, just like class redefinition affects live instances…