Creates a generic function and bind it to name.
You don’t usually need to use this, since the define-method
macro implicitly creates a generic function if it doesn’t exist yet.
You can pass a subclass of <generic>
to the class
keyword argument so that the created generic function will be the
instance of the passed class, instead of the default <generic>
class.
It is useful when you defined a subclass of <generic>
to customize
generic function application behavior.
Defines a method whose name is name. If there’s already a generic function object globally bound to name, the created method is added to the generic function. If name is unbound, or bound to an object except a generic function, then a new generic function is created, bound to name, then a new method is added to it.
The name can be followed by optional qualifiers, each of which is a keyword. Currently, only the following qualifier is valid.
:locked
Declares that you won’t redefine the method with the same specifiers. Attempt to redefine it will raise an error. (You can still define methods with different specifiers.)
Most methods concerning basic operations on built-in objects are locked, for redefining them would case Gauche’s infrastracture unstable. It also allows Gauche to perform certain optimizations.
Specs specifies the arguments and their types for this method. It’s like the argument list of lambda form, except you can specify the type of each argument.
specs : ( arg ... ) | ( arg ... . symbol ) | ( arg ... extended-spec ...) | symbol arg : ( symbol class ) | symbol
Class specifies the class that the argument has to belong to.
If arg
is just a symbol, it is equivalent to
(arg <top>)
. You can’t specify the type for
the “rest” argument, for it is always bound to a list.
You can use extended argument specifications such as
:optional
, :key
and :rest
as well.
(See Making procedures, for the explanation of extended
argument specifications). Those extended arguments are treated
as if a single “rest” argument in terms of dispatching; they
aren’t used for method dispatch, and you can’t specify classes for
these optional and keyword arguments.
The list of classes of the argument list is called
method specializer list, based on which the generic
function will select appropriate methods(s).
Here are some examples of specs and the corresponding
specializer list (note that the rest argument isn’t considered
as a part of specializer list; we know it’s always a list.)
The optional
item indicates whether the method takes
rest arguments or not.
specs: ((self <myclass>) (index <integer>) value) specializers: (<myclass> <integer> <top>) optional: #f specs: (obj (attr <string>)) specializers: (<top> <string>) optional: #f specs: ((self <myclass>) obj . options) specializers: (<myclass> <top>) optional: #t specs: ((self <myclass>) obj :optional (a 0) (b 1) :key (c 2)) specializers: (<myclass> <top>) optional: #t specs: args specializers: () optional: #t
If you define a method on name whose specializer list, and whether it takes rest arguments, match with one in the generic function’s methods, then the existing method is replaced by the newly defined one, unless the original method is locked.
Note: If you’re running Gauche with keyword-symbol integrated mode (see Keyword and symbol integration), there’s an ambiguity if you specify a keyword as the sole specs (to receive entire arguments in a single variable). Gauche parses keywords following name as qualifiers, so avoid using a keyword as such a variable.
When a generic function is applied, first it selects
methods whose specializer list matches the given arguments.
For example, suppose a generic function foo
has
three methods, whose specializer lists are
(<string> <top>)
, (<string> <string>)
,
and (<top> <top>)
, respectively.
When foo
is applied like (foo "abc" 3)
,
the first and the third method will be selected.
Then the selected methods are sorted from the most specific method to the least specific method. It is calculated as follows:
a
that has
specializers (A1 A2 …)
, and
a method b
that has (B1 B2 …)
.
An
and Bn
differ. Then the class of n-th argument is taken,
and its class precedence list is checked.
If An
comes before Bn
in the CPL, then
method a
is more specific than b
.
Otherwise, b
is more specific than a
.
a
and b
are the same,
except that one has an improper tail ("rest" argument)
and another doesn’t, then the method that doesn’t have an improper
tail is more specific than the one that has.
Once methods are sorted, the body of the first method is called with the actual argument.
Within the method body, a special local variable next-method
is bound implicitly.
This variable is bound within a method body to a special object that encapsulates the next method in the sorted method list.
Calling without arguments invokes the next method with the same arguments as this method is called with. Passing args … explicitly invokes the next method with the passed arguments.
If next-method
is called in the least specific method,
i.e. there’s no "next method", an error is signaled.