Generic functions and Objects

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;
      

The function tax could be invoked as tax(v) or 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 <truck> objects calls a special function named next-method. This function invokes the next most specific method of a generic function; in this case, the method for <vehicle> objects. Parameters to the current method get passed along automatically.

Technically, 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 Gwydion Project , currently requires the use of #next.

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 GetOwnerName and 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.