[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
3.5.1 Basic Generic Function Creation
The following forms may be used to bind a variable to a generic function. Depending on that variable's pre-existing value, the generic function may be created empty - with no methods - or it may contain methods that are inferred from the pre-existing value.
It is not, in general, necessary to use define-generic
or
define-accessor
before defining methods for the generic function
using define-method
, since define-method
will
automatically interpolate a define-generic
call, or upgrade an
existing generic to an accessor, if that is implied by the
define-method
call. Note in particular that,
if the specified variable already has a generic function value,
define-generic
and define-accessor
will discard it!
Obviously it is application-dependent whether this is desirable or not.
If, for example, you wanted to extend +
for a class representing
a new numerical type, you probably want to inherit any existing methods
for +
and so should not use define-generic
. If, on the
other hand, you do not want to risk inheriting methods whose behaviour
might surprise you, you can use define-generic
or
define-accessor
to wipe the slate clean.
- syntax: define-generic symbol
Create a generic function with name symbol and bind it to the variable symbol.
If the variable symbol was previously bound to a Scheme procedure (or procedure-with-setter), the old procedure (and setter) is incorporated into the new generic function as its default procedure (and setter). Any other previous value that was bound to symbol, including an existing generic function, is overwritten by the new generic function.
- syntax: define-accessor symbol
Create an accessor with name symbol and bind it to the variable symbol.
If the variable symbol was previously bound to a Scheme procedure (or procedure-with-setter), the old procedure (and setter) is incorporated into the new accessor as its default procedure (and setter). Any other previous value that was bound to symbol, including an existing generic function or accessor, is overwritten by the new definition.
It is sometimes tempting to use GOOPS accessors with short names. For
example, it is tempting to use the name x
for the x-coordinate
in vector packages.
Assume that we work with a graphical package which needs to use two
independent vector packages for 2D and 3D vectors respectively. If
both packages export x
we will encounter a name collision.
This can be resolved automagically with the duplicates handler
merge-generics
which gives the module system license to merge
all generic functions sharing a common name:
(define-module (math 2D-vectors) :use-module (oop goops) :export (x y ...)) (define-module (math 3D-vectors) :use-module (oop goops) :export (x y z ...)) (define-module (my-module) :use-module (math 2D-vectors) :use-module (math 3D-vectors) :duplicates merge-generics) |
The generic function x
in (my-module)
will now share
methods with x
in both imported modules.
There will, in fact, now be three distinct generic functions named
x
: x
in (2D-vectors)
, x
in
(3D-vectors)
, and x
in (my-module)
. The last
function will be an <extended-generic>
, extending the previous
two functions.
Let's call the imported generic functions the "ancestor functions".
The generic function x
in (my-module)
is, in turn, a
"descendant function" of the imported functions, extending its
ancestors.
For any generic function G, the applicable methods are selected from the union of the methods of the descendant functions, the methods of G itself and the methods of the ancestor functions.
This, ancestor functions share methods with their descendants and vice
versa. This implies that x
in (math 2D-vectors)
will
share the methods of x
in (my-module)
and vice versa,
while x
in (math 2D-vectors)
doesn't share the methods
of x
in (math 3D-vectors)
, thus preserving modularity.
Sharing is dynamic, so that adding new methods to a descendant implies adding it to the ancestor.
If duplicates checking is desired in the above example, the following
form of the :duplicates
option can be used instead:
:duplicates (merge-generics check) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |