Skip to content

Instantly share code, notes, and snippets.

@cwvh
Created December 9, 2011 05:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cwvh/1450378 to your computer and use it in GitHub Desktop.
Save cwvh/1450378 to your computer and use it in GitHub Desktop.
Example of asymmetric and symmetric multimethods.
from mm import multimethod, symmultimethod
class Ship(object):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class Asteroid(object):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
@multimethod(Ship, Asteroid)
def damage(ship, asteroid):
print '%s did insignificant damage to %s' % (ship, asteroid)
@multimethod(Asteroid, Ship)
def damage(asteroid, ship):
print '%s completely obliterated %s' % (asteroid, ship)
@symmultimethod(Ship, Asteroid)
def collide(a, b):
print 'bang!'
if __name__ == '__main__':
ship = Ship('Millennium Falcon')
asteroid = Asteroid('99942 Apophis')
damage(ship, asteroid)
damage(asteroid, ship)
collide(ship, asteroid)
collide(asteroid, ship)
# $ python game.py
# Millennium Falcon did insignificant damage to 99942 Apophis
# 99942 Apophis completely obliterated Millennium Falcon
# bang!
# bang!
# MultiMethod and multimethod, written by GvR (2005)
# http://www.artima.com/weblogs/viewpost.jsp?thread=101605
#
# SymmetricMultiMethod and symmultimethod, written by Kay Schluehr (2005)
# http://www.artima.com/forums/flat.jsp?forum=106&thread=101605
registry = {}
class MultiMethod(object):
def __init__(self, name, symmetric=False):
self.name = name
self.typemap = {}
def __call__(self, *args):
types = tuple(arg.__class__ for arg in args)
function = self.typemap.get(types)
if function is None:
raise TypeError("no match")
return function(*args)
def register(self, types, function):
if types in self.typemap:
raise TypeError("duplicate registration")
self.typemap[types] = function
class SymmetricMultiMethod(MultiMethod):
def __call__(self, *args):
types = tuple(sorted(arg.__class__ for arg in args))
function = self.typemap.get(types)
if function is None:
raise TypeError("no match")
return function(*args)
def multimethod(*types):
def register(function):
name = function.__name__
mm = registry.get(name)
if mm is None:
mm = registry[name] = MultiMethod(name)
mm.register(types, function)
return mm
return register
def symmultimethod(*types):
def register(function):
name = function.__name__
mm = registry.get(name)
if mm is None:
mm = registry[name] = SymmetricMultiMethod(name)
mm.register(tuple(sorted(types)), function)
return mm
return register
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment