/
interface.clj
113 lines (85 loc) · 5.7 KB
/
interface.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
(ns methodical.interface
(:refer-clojure :exclude [isa? prefers prefer-method])
(:require [potemkin.types :as p.types]))
(p.types/definterface+ MethodCombination
(allowed-qualifiers [method-combination]
"The set containg all qualifiers supported by this method combination. `nil` in the set means the method
combination supports primary methods (because primary methods have no qualifier); all other values refer to
auxiliary methods with that qualifer, e.g. `:before`, `:after`, or `:around`.
(allowed-qualifiers (clojure-method-combination)) ;-> #{nil}
(allowed-qualifiers (clos-method-combination)) ;-> #{nil :before :after :around}
(allowed-qualifiers (doseq-method-combination)) ;-> #{:doseq}")
(combine-methods [method-combination primary-methods aux-methods]
"Combine a sequence of matching `primary-methods` with `aux-methods` (a map of qualifier -> sequence of methods)
into a single effective method.")
(transform-fn-tail [method-combination qualifier fn-tail]
"Make appropriate transformations to the `fn-tail` of a `defmethod` macro expansion for a primary
method (qualifier will be `nil`) or an auxiliary method. You can use this method to add implicit args like
`next-method` to the body of a `defmethod` macro. (Because this method is invoked during macroexpansion, it should
return a Clojure form.)"))
(p.types/definterface+ MethodTable
(primary-methods [method-table]
"Get a `dispatch-value -> fn` map of all primary methods assoicated with this method table.")
(aux-methods [method-table]
"Get a `qualifier -> dispatch-value -> [fn]` map of all auxiliary methods associated with this method table.")
(add-primary-method [method-table dispatch-value f]
"Set the primary method implementation for `dispatch-value`, replacing it if it already exists.")
(remove-primary-method [method-table dispatch-value]
"Remove the primary method for `dispatch-value`.")
(add-aux-method [method-table qualifier dispatch-value f]
"Add an auxiliary method implementation for `qualifer` (e.g. `:before`) and `dispatch-value`. Unlike primary
methods, auxiliary methods are not limited to one method per dispatch value; thus this method does not remove
existing methods for this dispatch value. existing ")
(remove-aux-method [method-table qualifier dispatch-val method]
"Remove an auxiliary method from a method table. Because multiple auxiliary methods are allowed for the same
dispatch value, existing implementations of `MethodTable` are currently only able to remove exact matches -- for
functions, this usually means identical objects.
In the future, I hope to fix this by storing unique indentifiers in the metadata of methods in the map."))
(p.types/definterface+ Dispatcher
(dispatch-value
[dispatcher]
[dispatcher a]
[dispatcher a b]
[dispatcher a b c]
[dispatcher a b c d]
[dispatcher a b c d more]
"Return an appropriate dispatch value for args passed to a multimethod. (This method is equivalent in purpose to
the dispatch function of vanilla Clojure multimethods.)")
(matching-primary-methods [dispatcher method-table dispatch-value]
"Return a sequence of applicable primary methods for `dispatch-value`, sorted from most-specific to
least-specific. The standard dispatcher also checks to make sure methods in the sequence are not
ambiguously specific, replacing ambiguous methods with ones that will throw an Exception when invoked.")
(matching-aux-methods [dispatcher method-table dispatch-value]
"Return a map of aux method qualifier -> sequence of applicable methods for `dispatch-value`, sorted from
most-specific to least-specific.")
(default-dispatch-value [dispatcher]
"Default dispatch value to use if no other dispatch value matches.")
(prefers [dispatcher]
"Return a map of preferred dispatch value -> set of other dispatch values.")
(prefer-method [dispatcher dispatch-val-x dispatch-val-y]
"Prefer `dispatch-val-x` over `dispatch-val-y` for dispatch and method combinations."))
(p.types/definterface+ MultiFnImpl
(^methodical.interface.MethodCombination method-combination [multifn]
"Get the method combination associated with this multifn.")
(^methodical.interface.Dispatcher dispatcher [multifn]
"Get the dispatcher associated with this multifn.")
(^methodical.interface.MultiFnImpl with-dispatcher [multifn new-dispatcher]
"Return a copy of this multifn using `new-dispatcher` as its dispatcher.")
(^methodical.interface.MethodTable method-table [multifn]
"Get the method table associated with this multifn.")
(^methodical.interface.MultiFnImpl with-method-table [multifn new-method-table]
"Return a copy of this multifn using `new-method-table` as its method table.")
(effective-method [multifn dispatch-value]
"Return the effective method for `dispatch-value`. The effective method is a combined primary method and
applicable auxiliary methods that can be called like a normal function. `effective-method` is similar in purpose
to `get-method` in vanilla Clojure multimethods; a different name is used here because I felt `get-method` would
be ambiguous with regards to whether it returns only a primary method or a combined effective method."))
(p.types/definterface+ Cache
(cached-method [cache dispatch-value]
"Return cached effective method for `dispatch-value`, if it exists in the cache.")
(cache-method! [cache dispatch-value method]
"Cache the effective method for `dispatch-value` in this cache.")
(clear-cache! [cache]
"Empty the contents of the cache in-place.")
(^methodical.interface.Cache empty-copy [cache]
"Return an empty copy of the same type as this cache, e.g. for use when copying a multifn."))