~ / track B / clojure advanced
Protocols and multimethods
AdvancedClojure offers two different "polymorphism" tools. Protocols dispatch on the type of the first argument and compile down to fast JVM method calls. Multimethods dispatch on the result of an arbitrary function — type, a keyword, a tuple, anything you can compute. Protocols are for the common "behave-like-this-thing" case; multimethods are for everything else.
Minimal example: a protocol
A protocol declares a small interface, and any number of types can extend it.
Protocols are open: a new file can come along and extend-protocol to types
the protocol's author never imagined, without modifying the original code.
Records implement protocols natively
defrecord creates a Java class that can implement protocols inline, which is
the typical "object-like" pattern in Clojure:
Multimethods dispatch on anything
Where a protocol asks "what type is this?", a multimethod asks "what should I look up in the method table?". The dispatch function computes the key.
The dispatch function can return a tuple, enabling a kind of double dispatch:
When to use which
- Protocol: you have a small, fixed set of operations and you want them fast; dispatch is naturally per-type; you might also use a record.
- Multimethod: dispatch depends on data (a keyword field, a tuple, a
hierarchy via
derive); flexibility matters more than raw speed.
Check yourself
? quiz
A new payment method ships and you want to extend an existing protocol to it. Do you need to modify the protocol's source file?
Exercise
Define a multimethod tax-of that dispatches on :country and computes a tax
amount from :price. Implement :br (10%), :us (7%), and a :default of 0.