A generic function represents zero or more similar methods. Every method created by means of define method is automatically contained within the generic function of the same name. For example, a programmer could define three methods named display , each of which acted on a different data type:
define method display(i :: <integer>) do-display-integer(i); end; define method display(s :: <string>) do-display-string(s); end; define method display(f :: <float>) do-display-float(f); end;
When a program calls display, Dylan examines all three methods. Depending on the number and type of arguments to display, Dylan invokes one of the above methods. If no methods match the actual parameters, an error occurs.
In C++, this process occurs only at compile time. (It's called operator overloading.) In Dylan, calls to display may be resolved either at compile time or while the program is actually executing. This makes it possible to define methods like:
define method display(c :: <collection>) for (item in c) display(item); // runtime dispatch end; end;
This method extracts objects of unknown type from a collection, and attempts to invoke the generic function display on each of them. Since there's no way for the compiler to know what type of objects the collection actually contains, it must generate code to identify and invoke the proper method at runtime. If no applicable method can be found, the Dylan runtime environment throws an exception.
Generic functions may also be declared explicity, allowing the programmer to exercise control over what sort of methods get added. For example, the following declaration limits all display methods to single parameter and no return value:
define generic display(thing :: <object>) => ()
Generic functions are explained in greater detail in the chapter on multiple dispatch.