#lang scribble/doc @(require scribble/manual (for-label scheme "../overloads.ss" "../multimethod.ss")) @title[#:tag "multimethod" #:style '(toc)]{Multimethods} @defmodule[(planet "multimethod.ss" ("murphy" "multimethod.plt" 2 0))]{ This module provides procedures and syntactic sugar to create multimethods and to attach procedures to them. Each multimethod is a structure that can act as a procedure accepting any number of arguments and any keyword arguments. When called, it first applies a signature generator to its arguments and keyword arguments, which should produce a single result. This generated signature is then compared with the signatures for registered method implementations to find the one to call. See @scheme[find-method] for a precise explanation of how methods are looked up. This module also re-exports the @scheme[exn:fail:multimethod] structure defined in @schememodname["overloads.ss"]. } @section{Procedural Protocol} @defproc[(make-multimethod [make-signature procedure?] [#:overloads overloads overloads? (make-overloads)]) multimethod?]{ Creates a multimethod structure that can be called as a procedure. @scheme[make-signature] is the signature generator procedure applied every time the multimethod is called to determine the signature of its arguments. The actual method implementation to call is then looked up in the overload set @scheme[os]. The overloads are stored in a parameter. This way you can have the advantages of parameterization, which can be handy for dynamically adding or removing methods or preferences, without syntactic differences to regular procedures when calling the multimethod. } @defproc[(multimethod? [v any/c]) boolean?]{ Checks whether the given object is a multimethod. } @defproc[(multimethod-make-signature [mm multimethod?]) procedure?]{ Retrieves the signature generator of a multimethod. } @defproc[(multimethod-current-overloads [mm multimethod?]) (parameter/c overloads?)]{ Extracts the parameter object holding the overloads from a multimethod. } @section{Syntactic Sugar} @defform/subs[#:literals (::) (define-multimethod name+args :: signature options ...) ([name+args (name . args) name])]{ Expands to a @scheme[define] form assigning a multimethod to @scheme[name]. If @scheme[args] are given, @scheme[signature] is implicitly wrapped in a lambda expression with @scheme[args] as arguments. Otherwise @scheme[signature] must evaluate to a procedure. In either case the resulting procedure becomes the signature generator of the new multimethod. The @scheme[options] are passed on to @scheme[make-multimethod] and may be used to specify keyword arguments. } @defform[(parameterize-multimethod (name ...) expr ...) #:contracts ([name multimethod?])]{ Extracts the parameter objects holding the current overloads from the multimethods given by @scheme[name ...] and parameterizes them to their current values for the dynamic extent of @scheme[expr ...]. This is useful to install methods or preferences temporarily. } @defform*/subs[#:literals (::) [(define-method name+args #:default method ...) (define-method name+args :: signature method ...)] ([name+args (name . args) name]) #:contracts ([name multimethod?])]{ Attaches a new method implementation to the multimethod @scheme[name] or removes an existing one, modifying the value of the parameter holding the current overloads. The signature for the new method is either the default signature of the multimethod, if @scheme[#:default] is specified, or the given @scheme[signature]. @scheme[signature] is implicitly quasiquoted. If @scheme[args] are given, the method body specified by @scheme[method ...] is implicitly wrapped in a lambda expression with @scheme[args] as arguments. Otherwise @scheme[method] must be a single expression evaluating to a procedure. In either case the resulting procedure becomes the method implementation. If no @scheme[args] are given and @scheme[method] evaluates to @scheme[#f], any existing implementation for the given signature is removed. } @defform/subs[#:literals (:: < > =) (define-preference name :: preference) ([preference (< signature-a signature-b) (> signature-a signature-b) (= signature-a signature-b)])]{ Attaches a new preference to the multimethod @scheme[name] or removes an existing one, modifying the value of the parameter holding the current overloads. The given signatures are implicitly quasiquoted. The type of preference registered or unregistered depends on the form of @scheme[preference]: @itemize{ @item{ If @scheme[(< signature-a signature-b)] is specified, @scheme[signature-a] is registered as preferred to @scheme[signature-b]. } @item{ If @scheme[(> signature-a signature-b)] is specified, @scheme[signature-b] is registered as preferred to @scheme[signature-a]. } @item{ If @scheme[(= signature-a signature-b)] is specified, any preference of @scheme[signature-a] over @scheme[signature-b] or vice versa is removed. } } }