Methodical versions of vanilla Clojure [[defmulti]] and [[defmethod]] macros.
(defmethod multifn-symb dispatch-val docstring? & fn-tail)
(defmethod multifn-symb
aux-qualifier
dispatch-val
unique-key?
docstring?
&
fn-tail)
Define a new multimethod method implementation. Syntax is the same as for vanilla Clojure defmethod
, but you may
also define auxiliary methods by passing an optional auxiliary method qualifier before the dispatch value:
;; define a new primary method
(defmethod some-multifn Bird
[_]
...)
;; define a new *auxiliary* method
(defmethod some-multifn :before Toucan
[_]
...)
Define a new multimethod method implementation. Syntax is the same as for vanilla Clojure [[defmethod]], but you may also define auxiliary methods by passing an optional auxiliary method qualifier before the dispatch value: ```clj ;; define a new primary method (defmethod some-multifn Bird [_] ...) ;; define a new *auxiliary* method (defmethod some-multifn :before Toucan [_] ...) ```
(defmulti name-symb
docstring?
attr-map?
&
{:keys [dispatcher combo method-table cache]})
(defmulti name-symb
docstring?
attr-map?
dispatch-fn?
&
{:keys [hierarchy default-value prefers combo method-table cache]})
Creates a new Methodical multimethod named by a Var. Usage of this macro mimics usage of [[clojure.core/defmulti]],
and it can be used as a drop-in replacement; it does, however, support a larger set of options. Note the dispatch-fn
is optional (if omitted, then identity will be used). In addition to the usual :default
and :hierarchy
options,
you many specify:
:combo
- The method combination to use for this multimethods. Method combinations define how multiple applicable
methods are combined; which auxiliary methods, e.g. :before
or :after
methods, are supported; and whether other
advanced facilities, such as next-method
, are available. There are over a dozen method combinations that ship as
part of Methodical; many are inspired by their equivalents in the Common Lisp Object System. The default method
combination is the thread-last method combination.
:dispatcher
- The dispatcher handles dispatch values when invoking a multimethod, and whether one dispatch value
(and thus, whether its corresponding method) is considered to be more-specific or otherwise preferred over another
dispatch value. The default dispatcher largely mimics the behavior of the Clojure dispatcher, using a single
hierarchy augmented by a prefers
table to control dispatch, with one big improvement: when dispatching on
multiple values, it supports default methods that specialize on some args and use the default for others.
(e.g. [String :default]
)
Note that the :hierarchy
, :default-value
and the positional dispatch-fn
are provided as conveniences for
creating a default dispatcher; if you pass a :dispatcher
arg instead, those arguments are not required and will
be ignored.
:cache
- controls caching behavior for effective methods. The default simple cache mimics the behavior of vanilla
Clojure multimethods.
:method-table
- maintains tables of dispatch value -> primary method and auxiliary method qualifier -> dispatch
value -> methods. The default implementation is a pair of simple maps.
The above options comprise the main constituent parts of a Methodical multimethod, and the majority of those parts
have several alternative implementations available in methodical.impl
. Defining additional implementations is
straightforward as well: see methodical.interface
for more details.
Other improvements over [[clojure.core/defmulti]]:
Attribute map options:
defmulti
supports a few additional options in its attributes map that will be used to validate defmethod
forms
during macroexpansion time. These are meant to help the users of your multimethods use them correctly by catching
mistakes right away rather than waiting for them to pull their hair out later wondering why a method they added isn't
getting called.
:dispatch-value-spec
-- a spec for the defmethod
dispatch value:
(m/defmulti mf
{:arglists '([x y]), :dispatch-value-spec (s/cat :x keyword?, :y int?)}
(fn [x y] [x y]))
(m/defmethod mf [:x 1]
[x y]
{:x x, :y y})
;; => ok
(m/defmethod mf [:x]
[x y]
{:x x, :y y})
;; failed: Insufficient input in: [0] at: [:args-for-method-type :primary :dispatch-value :y] [:x]
Note that this spec is applied to the unevaluated arguments at macroexpansion time, not the actual evaluated values.
Note also that if you want to allow a :default
method your spec will have to support it.
:defmethod-arities
-- a set of allowed/required arities that defmethod
forms are allowed to have. defmethod
forms must have arities that match all of the specified :defmethod-arities
, and all of its arities must be
allowed by :defmethod-arities
:
(m/defmulti ^:private mf
{:arglists '([x]), :defmethod-arities #{1}}
keyword)
(m/defmethod mf :x [x] x)
;; => ok
(m/defmethod mf :x ([x] x) ([x y] x y))
;; => error: {:arities {:disallowed #{2}}}
(m/defmethod mf :x [x y] x y)
;; => error: {:arities {:required #{1}}}
(m/defmethod mf :x [x y] x)
;; => error: {:arities {:required #{1 [:>= 3]}, :disallowed #{2}}}
:defmethod-arities
must be a set of either integers or [:> n]
forms to represent arities with &
rest
arguments, e.g. [:>= 3]
to mean an arity of three or-more arguments:
;; methods must both a 1-arity and a 3+-arity
(m/defmulti ^:private mf
{:arglists '([x] [x y z & more]), :defmethod-arities #{1 [:>= 3]}}
keyword)
(m/defmethod mf :x ([x] x) ([x y z & more] x))
;; => ok
When rest-argument arities are used, Methodical is smart enough to allow them when appropriate even if they do not
specifically match an arity specified in :defmethod-arities
:
(m/defmulti ^:private mf
{:arglists '([x y z & more]), :defmethod-arities #{[:>= 3]}}
keyword)
(m/defmethod mf :x
([a b c] x)
([a b c d] x)
([a b c d & more] x))
;; => ok, because everything required by [:>= 3] is covered, and everything present is allowed by [:>= 3]
Creates a new Methodical multimethod named by a Var. Usage of this macro mimics usage of [[clojure.core/defmulti]], and it can be used as a drop-in replacement; it does, however, support a larger set of options. Note the dispatch-fn is optional (if omitted, then identity will be used). In addition to the usual `:default` and `:hierarchy` options, you many specify: * `:combo` - The method combination to use for this multimethods. Method combinations define how multiple applicable methods are combined; which auxiliary methods, e.g. `:before` or `:after` methods, are supported; and whether other advanced facilities, such as `next-method`, are available. There are over a dozen method combinations that ship as part of Methodical; many are inspired by their equivalents in the Common Lisp Object System. The default method combination is the thread-last method combination. * `:dispatcher` - The dispatcher handles dispatch values when invoking a multimethod, and whether one dispatch value (and thus, whether its corresponding method) is considered to be more-specific or otherwise preferred over another dispatch value. The default dispatcher largely mimics the behavior of the Clojure dispatcher, using a single hierarchy augmented by a `prefers` table to control dispatch, with one big improvement: when dispatching on multiple values, it supports default methods that specialize on some args and use the default for others. (e.g. `[String :default]`) Note that the `:hierarchy`, `:default-value` and the positional `dispatch-fn` are provided as conveniences for creating a default dispatcher; if you pass a `:dispatcher` arg instead, those arguments are not required and will be ignored. * `:cache` - controls caching behavior for effective methods. The default simple cache mimics the behavior of vanilla Clojure multimethods. * `:method-table` - maintains tables of dispatch value -> primary method and auxiliary method qualifier -> dispatch value -> methods. The default implementation is a pair of simple maps. The above options comprise the main constituent parts of a Methodical multimethod, and the majority of those parts have several alternative implementations available in [[methodical.impl]]. Defining additional implementations is straightforward as well: see [[methodical.interface]] for more details. Other improvements over [[clojure.core/defmulti]]: * Evaluating the form a second time (e.g., when reloading a namespace) will *not* redefine the multimethod, unless you have modified its form -- unlike vanilla Clojure multimethods, which need to be unmapped from the namespace to make such minor tweaks as changing the dispatch function. Attribute map options: `defmulti` supports a few additional options in its attributes map that will be used to validate `defmethod` forms during macroexpansion time. These are meant to help the users of your multimethods use them correctly by catching mistakes right away rather than waiting for them to pull their hair out later wondering why a method they added isn't getting called. * `:dispatch-value-spec` -- a spec for the `defmethod` dispatch value: ```clj (m/defmulti mf {:arglists '([x y]), :dispatch-value-spec (s/cat :x keyword?, :y int?)} (fn [x y] [x y])) (m/defmethod mf [:x 1] [x y] {:x x, :y y}) ;; => ok (m/defmethod mf [:x] [x y] {:x x, :y y}) ;; failed: Insufficient input in: [0] at: [:args-for-method-type :primary :dispatch-value :y] [:x] ``` Note that this spec is applied to the unevaluated arguments at macroexpansion time, not the actual evaluated values. Note also that if you want to allow a `:default` method your spec will have to support it. * `:defmethod-arities` -- a set of allowed/required arities that `defmethod` forms are allowed to have. `defmethod` forms must have arities that match *all* of the specified `:defmethod-arities`, and all of its arities must be allowed by `:defmethod-arities`: ```clj (m/defmulti ^:private mf {:arglists '([x]), :defmethod-arities #{1}} keyword) (m/defmethod mf :x [x] x) ;; => ok (m/defmethod mf :x ([x] x) ([x y] x y)) ;; => error: {:arities {:disallowed #{2}}} (m/defmethod mf :x [x y] x y) ;; => error: {:arities {:required #{1}}} (m/defmethod mf :x [x y] x) ;; => error: {:arities {:required #{1 [:>= 3]}, :disallowed #{2}}} ``` `:defmethod-arities` must be a set of either integers or `[:> n]` forms to represent arities with `&` rest arguments, e.g. `[:>= 3]` to mean an arity of three *or-more* arguments: ```clj ;; methods must both a 1-arity and a 3+-arity (m/defmulti ^:private mf {:arglists '([x] [x y z & more]), :defmethod-arities #{1 [:>= 3]}} keyword) (m/defmethod mf :x ([x] x) ([x y z & more] x)) ;; => ok ``` When rest-argument arities are used, Methodical is smart enough to allow them when appropriate even if they do not specifically match an arity specified in `:defmethod-arities`: ```clj (m/defmulti ^:private mf {:arglists '([x y z & more]), :defmethod-arities #{[:>= 3]}} keyword) (m/defmethod mf :x ([a b c] x) ([a b c d] x) ([a b c d & more] x)) ;; => ok, because everything required by [:>= 3] is covered, and everything present is allowed by [:>= 3] ```
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close