#lang scribble/doc @(require scribble/manual scribble/eval (for-label scheme "../main.ss")) @title{Multimethods} @table-of-contents[] @defmodule[(planet "main.ss" ("murphy" "multimethod.plt" 2 1))]{ Provides procedures with versatile dispatch on any number of their arguments. Inheritance hierarchies for method signatures can be defined in an ad-hoc fashion or class and interface hierarchies from @schememodname[scheme/class] can be used. This main module re-exports all bindings from @scheme["hierarchy.ss"], @scheme["overloads.ss"] and @scheme["multimethod.ss"]. } @define[sandbox (let ([sandbox (make-base-eval)]) (sandbox '(require "main.ss")) sandbox)] The usage of the module is best demonstrated with some examples before one reads the API reference. We start with the definition of a global hierarchy: @defs+int[ #:eval sandbox ( (derive 'rock 'item) (derive 'paper 'item) (derive 'scissors 'item) ) (derived? 'rock 'item) (derived? 'rock 'rock) (derived? 'rock 'paper) (descendants 'item) ] Given this hierarchy of objects we can easily define a multimethod reflecting the rules of a well known game: @defs+int[ #:eval sandbox ( (define-multimethod (beats? a b) :: (vector-immutable a b)) (define-method (beats? a b) :: #(item item) #f) (define-method (beats? a b) :: #(rock scissors) #t) (define-method (beats? a b) :: #(paper rock) #t) (define-method (beats? a b) :: #(scissors paper) #t) ) (beats? 'rock 'paper) (beats? 'rock 'scissors) ] Unknown objects are not recognized, of course: @interaction[ #:eval sandbox (ancestors 'limestone) (beats? 'limestone 'scissors) ] But the hierarchy is dynamic and we can fix this: @def+int[ #:eval sandbox (derive 'limestone 'rock) (ancestors 'limestone) (beats? 'limestone 'scissors) ] The global hierarchy can be parameterized: @interaction[ #:eval sandbox (parameterize ([global-hierarchy (derive (global-hierarchy) 'marble 'rock)]) (beats? 'marble 'scissors)) (beats? 'marble 'scissors) ] Since multimethods store their method overload sets in parameters, their behaviour can also be changed temporarily: @interaction[ #:eval sandbox (parameterize-multimethod (beats?) (define-method beats? :: #(rock scissors) #f) (beats? 'limestone 'scissors)) (beats? 'limestone 'scissors) (parameterize-multimethod (beats?) (define-method (beats? a b) :: #(limestone paper) #t) (beats? 'limestone 'paper)) (beats? 'limestone 'paper) ] Occasionally it may happen that the type hierarchy and method definitions result in an ambiguous situation: @defs+int[ #:eval sandbox ( (derive 'limestone 'sedimentary) (define-method (beats? a b) :: #(sedimentary scissors) #f) ) (beats? 'limestone 'scissors) ] This can be resolved by preferences or more specific definitions: @interaction[ #:eval sandbox (parameterize-multimethod (beats?) (define-preference beats? :: (< #(rock scissors) #(sedimentary scissors))) (beats? 'limestone 'scissors)) (parameterize-multimethod (beats?) (define-preference beats? :: (> #(rock scissors) #(sedimentary scissors))) (beats? 'limestone 'scissors)) (parameterize-multimethod (beats?) (define-method (beats? a b) :: #(limestone scissors) 'foobar) (beats? 'limestone 'scissors)) ] Methods for more specific signatures may also call the next less specific method, iff that method is uniquely determined: @def+int[ #:eval sandbox (define-method (beats? a b) :: #(limestone scissors) (and (call-next-method) 'foobar)) (beats? 'limestone 'scissors) (parameterize-multimethod (beats?) (define-preference beats? :: (< #(rock scissors) #(sedimentary scissors))) (beats? 'limestone 'scissors)) (parameterize-multimethod (beats?) (define-preference beats? :: (> #(rock scissors) #(sedimentary scissors))) (beats? 'limestone 'scissors)) ] @include-section["hierarchy.scrbl"] @include-section["overloads.scrbl"] @include-section["multimethod.scrbl"] @section{License} Copyright (c) 2009 by @link["mailto:chust@web.de"]{Thomas Chust @""}. This package is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You can find a copy of the GNU Lesser General Public License at @link["http://www.gnu.org/licenses/lgpl-3.0.html"]{http://www.gnu.org/licenses/lgpl-3.0.html}.