Generic functions, introduced in Methods and Generic functions , provide the equivalent of C++ and Object Pascal member functions. In the simplest case, just declare a generic function which dispatches on the first parameter.
define generic tax(v :: <vehicle>) => tax-in-dollars :: <float>; define method tax(v :: <vehicle>) => tax-in-dollars :: <float>; 100.00; end; //=== Two new subclasses of vehicle define class <car> (<vehicle>) end; define class <truck> (<vehicle>) slot capacity, required-init-keyword: tons:; end; //=== Two new "tax" methods define method tax( c :: <car> ) => tax-in-dollars :: <float>; 50.00; end method; define method tax( t :: <truck> ) => tax-in-dollars :: <float>; // standard vehicle tax plus $10/ton next-method( ) + t.capacity * 10.00; end method;
tax could be invoked as
v.tax, because it
only has one argument. Generic functions with two or more arguments
must be invoked in the usual Dylan fashion; no syntactic sugar exists
to make them look like C++ member functions.
The version of tax for
calls a special function named
function invokes the next most specific method of a generic function;
in this case, the method for
objects. Parameters to the current method get passed along
next-method is a special
parameter to a method, and may be passed explicitly using
#next. mindy, a popular but incomplete bytecode compiler
written as part of the
, currently requires the use of
define method tax(t :: <truck>, #next next-method) => tax-in-dollars :: <float>; // standard vehicle tax plus $10/ton next-method() + t.capacity * 10.00; end method;
Dylan's separation of classes and generic functions provides some interesting design ideas. Classes no longer need to “contain ” their member functions; it's possible to write a new generic function without touching the class definition. For example, a module handling traffic simulations and one handling municipal taxes could each have many generic functions involving vehicles, but both could use the same vehicle class.
Slots in Dylan may also be replaced by programmer-defined accessor
functions, all without modifying existing clients of the class. The
Dylan Reference Manual
describes numerous ways to accomplish the change; several should
be apparent from the preceding discussion. This flexibility frees
programmers from creating functions like
SetOwnerName, not to mention the
corresponding private member variables and constructor code.
For even more creative uses of generic functions and the Dylan object model, see the chapter on Multiple Dispatch.