#lang scribble/doc @(require scribble/manual (for-label scheme "../hierarchy.ss" "../overloads.ss")) @title[#:tag "overloads" #:style '(toc)]{Sets of Overloaded Methods} @defmodule[(planet "overloads.ss" ("murphy" "multimethod.plt" 2 0))]{ This module provides procedures to manage sets of overloaded methods. It's the backend doing all the work behind multimethods. } @defproc[(make-overloads [#:default default-signature any/c #f] [#:hierarchy ref-hierarchy (-> hierarchy?) global-hierarchy]) overloads?]{ Creates a new overload set. @scheme[default-signature] is a default signature that is looked up in the method tables if the one passed to @scheme[find-method] doesn't match any implementation. @scheme[ref-hierarchy] is a procedure yielding the value hierarchy to be used by signature comparisons, it defaults to @scheme[global-hierarchy], ie. the default behaviour is to read the current value of the global hierarchy parameter every time the hierarchy is needed. } @defproc[(overloads? [v any/c]) boolean?]{ Checks whether the given object is an overload set. } @defproc[(overloads-default-signature [m overloads?]) any/c]{ Retrieves the default signature of an overload set. } @defproc[(set-method [os overloads?] [signature any/c] [method procedure?]) overloads?]{ Takes the overloads @scheme[os] and transforms them into new overloads that map the given @scheme[signature] to the method implementation @scheme[method]. Any existing mapping for the given @scheme[signature] is replaced. } @defproc[(remove-method [os overloads?] [signature any/c]) overloads?]{ Takes the overloads @scheme[os] and transforms them into new overloads that have no direct mapping for the given @scheme[signature] to any method implementation. } @defproc[(prefer-method [os overloads?] [signature-a any/c] [signature-b any/c]) overloads?]{ Takes the overloads @scheme[os] and transforms them into new overloads that prefer dispatching via @scheme[signature-a] over dispatching via @scheme[signature-b]. } @defproc[(unprefer-method [os overloads?] [signature-a any/c] [signature-b any/c]) overloads?]{ Takes the overloads @scheme[os] and transforms them into new overloads that do not prefer dispatching via @scheme[signature-a] over dispatching via @scheme[signature-b]. } @defstruct[(exn:fail:multimethod exn:fail) ([overloads overloads?] [signature any/c])]{ An exception raised to signal a problem with multimethod dispatch. @scheme[find-method] raises it to indicate that the @scheme[overloads] contain no matching method for @scheme[signature]. } @defproc[(find-method [os overloads?] [signature any/c]) procedure?]{ Retrieves the method implementation from overloads @scheme[os] that matches the given @scheme[signature] best. The method lookup works as follows: @itemize{ @item{ The current hierarchy used by the overload set is retrieved using the getter procedure passed to @scheme[make-overloads]. If this value changed since the last time the overload set was asked to find a method, the new value is stored and the dispatching cache of the overload set is cleared, ie. it is reset to the same state in which it was created. } @item{ The dispatching cache is consulted to find a method for the signature. If one is found, the search terminates. The result of subsequent search steps is later stored in the cache. } @item{ The method table is consulted to find a method directly associated with the signature. If one is found, the search terminates here. } @item{ A list of possible method implementations is built: @itemize{ @item{ All ancestors of the signature registered in the hierarchy used by the overload set are retrieved. Then any methods associated to those ancestor signatures are fetched from the method table. } @item{ If the signature satisfies @scheme[class?], @scheme[interface?] or @scheme[dict?], the whole method table is scanned for mappings from candidate signatures that are ancestors of the reference signature as determined by @scheme[derived?]. } } All method implementations found in this way are sorted by their signatures. A signature sorts before another if one of the following conditions is met: @itemize{ @item{ The first signature is @scheme[derived?] from the second one. } @item{ The first signature is registered as preferred to the second one. } @item{ There is a registered preference such that the first signature is @scheme[derived?] from the preferred signature while the less preferred signature is @scheme[derived?] from the second signature. } } If the resulting sorted list has exactly one entry, or if the first entry sorts strictly before all others, the first entry of the list is used as the method implementation to call and the search terminates here. If the list has multiple entries but the first one does not sort strictly before all others, an error is raised indicating ambiguous methods. You can resolve this situation by defining more specific methods or by registering preferences. } @item{ If no method implementation was found so far, the search is retried from using not the original signature, but the overload set's default signature. } @item{ If all steps up to now have failed to find a method. An exception of type @scheme[exn:fail:multimethod] is raised indicating a lack of applicable method implementations. } } }