#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 1))]{ 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-methods] 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-methods] raises it to indicate that the @scheme[overloads] contain no matching method for @scheme[signature]. } @defproc[(find-methods [os overloads?] [signature any/c]) (listof procedure?)]{ Retrieves all method implementations from overloads @scheme[os] that match the given @scheme[signature] and that can be strictly ordered by specificity or preference. 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 list for the signature. If one is found, the search terminates. The result of subsequent search steps is later stored in the cache. } @item{ A list of possible method implementations is built: @itemize{ @item{ The method table is consulted to find a method directly associated with the signature. } @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, this list of one method is used and the search terminates here. If the list has multiple entries, the longest prefix of the list that is strictly sorted is determined. If this prefix is not empty, it is used as the list of methods and the search terminates here. If the list has multiple entries but the first one does not sort strictly before all others, an exception of type @scheme[exn:fail:multimethod] 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 the second step 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. } } }