From c2b20996568389cf33a879a1540e88bc943d426d Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Thu, 12 Sep 2019 10:59:10 +0400 Subject: [PATCH 1/9] MethodCombination interface --- src/methodical/impl/combo/clojure.clj | 6 ++--- src/methodical/impl/combo/clos.clj | 6 ++--- src/methodical/impl/combo/operator.clj | 6 ++--- src/methodical/impl/combo/threaded.clj | 7 +++--- src/methodical/impl/standard.clj | 6 ++--- src/methodical/interface.clj | 34 +++++++++++++++++--------- 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/methodical/impl/combo/clojure.clj b/src/methodical/impl/combo/clojure.clj index 813c103..b1b1c18 100644 --- a/src/methodical/impl/combo/clojure.clj +++ b/src/methodical/impl/combo/clojure.clj @@ -15,13 +15,13 @@ (instance? ClojureMethodCombination another)) MethodCombination - (allowed-qualifiers [_] + (allowedQualifiers [_] #{nil}) ; only primary methods - (combine-methods [_ [primary-method] aux-methods] + (combineMethods [_ [primary-method] aux-methods] (when (seq aux-methods) (throw (UnsupportedOperationException. "Clojure-style multimethods do not support auxiliary methods."))) primary-method) - (transform-fn-tail [_ _ fn-tail] + (transformFnTail [_ _ fn-tail] fn-tail)) diff --git a/src/methodical/impl/combo/clos.clj b/src/methodical/impl/combo/clos.clj index b4b289e..7e39221 100644 --- a/src/methodical/impl/combo/clos.clj +++ b/src/methodical/impl/combo/clos.clj @@ -63,14 +63,14 @@ (instance? CLOSStandardMethodCombination another)) MethodCombination - (allowed-qualifiers [_] + (allowedQualifiers [_] #{nil :before :after :around}) - (combine-methods [_ primary-methods {:keys [before after around]}] + (combineMethods [_ primary-methods {:keys [before after around]}] (some-> (combo.common/combine-primary-methods primary-methods) (apply-befores before) (apply-afters after) (combo.common/apply-around-methods around))) - (transform-fn-tail [_ qualifier fn-tail] + (transformFnTail [_ qualifier fn-tail] (combo.common/add-implicit-next-method-args qualifier fn-tail))) diff --git a/src/methodical/impl/combo/operator.clj b/src/methodical/impl/combo/operator.clj index ce5e161..67eb401 100644 --- a/src/methodical/impl/combo/operator.clj +++ b/src/methodical/impl/combo/operator.clj @@ -163,15 +163,15 @@ (= operator-name (.operator-name ^OperatorMethodCombination another)))) MethodCombination - (allowed-qualifiers [_] + (allowedQualifiers [_] #{nil :around}) - (combine-methods [_ primary-methods {:keys [around]}] + (combineMethods [_ primary-methods {:keys [around]}] (when (seq primary-methods) (-> ((operator operator-name) primary-methods) (combo.common/apply-around-methods around)))) - (transform-fn-tail [_ qualifier fn-tail] + (transformFnTail [_ qualifier fn-tail] (if (= qualifier :around) (combo.common/add-implicit-next-method-args qualifier fn-tail) fn-tail))) diff --git a/src/methodical/impl/combo/threaded.clj b/src/methodical/impl/combo/threaded.clj index 688d916..54942e5 100644 --- a/src/methodical/impl/combo/threaded.clj +++ b/src/methodical/impl/combo/threaded.clj @@ -75,20 +75,19 @@ (pretty [_] (list 'threading-method-combination threading-type)) - MethodCombination Object (equals [_ another] (and (instance? ThreadingMethodCombination another) (= threading-type (.threading-type ^ThreadingMethodCombination another)))) MethodCombination - (allowed-qualifiers [_] + (allowedQualifiers [_] #{nil :before :after :around}) - (combine-methods [_ primary-methods aux-methods] + (combineMethods [_ primary-methods aux-methods] (combine-with-threader (threading-invoker threading-type) primary-methods aux-methods)) - (transform-fn-tail [_ qualifier fn-tail] + (transformFnTail [_ qualifier fn-tail] (combo.common/add-implicit-next-method-args qualifier fn-tail))) (defn threading-method-combination diff --git a/src/methodical/impl/standard.clj b/src/methodical/impl/standard.clj index cf60bfc..e214190 100644 --- a/src/methodical/impl/standard.clj +++ b/src/methodical/impl/standard.clj @@ -50,13 +50,13 @@ (StandardMultiFn. impl new-meta))) MethodCombination - (allowed-qualifiers [_] + (allowedQualifiers [_] (i/allowed-qualifiers (i/method-combination impl))) - (combine-methods [_ primary-methods aux-methods] + (combineMethods [_ primary-methods aux-methods] (i/combine-methods (i/method-combination impl) primary-methods aux-methods)) - (transform-fn-tail [_ qualifier fn-tail] + (transformFnTail [_ qualifier fn-tail] (i/transform-fn-tail (i/method-combination impl) qualifier fn-tail)) Dispatcher diff --git a/src/methodical/interface.clj b/src/methodical/interface.clj index d587059..c78d696 100644 --- a/src/methodical/interface.clj +++ b/src/methodical/interface.clj @@ -2,25 +2,35 @@ (: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 +(definterface MethodCombination + (allowedQualifiers []) + (combineMethods [primary-methods aux-methods]) + (transformFnTail [qualifier fn-tail])) + +(defn allowed-qualifiers + "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 + (allowed-qualifiers (doseq-method-combination)) ;-> #{:doseq}" + [^MethodCombination method-combination] + (.allowedQualifiers method-combination)) + +(defn combine-methods + "Combine a sequence of matching `primary-methods` with `aux-methods` (a map of qualifier -> sequence of methods) + into a single effective method." + [^MethodCombination method-combination primary-methods aux-methods] + (.combineMethods method-combination primary-methods aux-methods)) + +(defn transform-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.)")) + return a Clojure form.)" + [^MethodCombination method-combination qualifier fn-tail] + (.transformFnTail method-combination qualifier fn-tail)) (p.types/definterface+ MethodTable (primary-methods [method-table] From 28c55b84fa90e7607ffd541d234413ef0f817306 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Thu, 12 Sep 2019 11:46:06 +0400 Subject: [PATCH 2/9] Dispatcher interface --- src/methodical/impl/dispatcher/everything.clj | 22 +-- src/methodical/impl/dispatcher/standard.clj | 20 +-- src/methodical/impl/method_table/clojure.clj | 12 +- src/methodical/impl/method_table/standard.clj | 12 +- src/methodical/impl/standard.clj | 58 +++---- src/methodical/interface.clj | 147 +++++++++++------- .../impl/dispatcher/standard_test.clj | 4 +- 7 files changed, 158 insertions(+), 117 deletions(-) diff --git a/src/methodical/impl/dispatcher/everything.clj b/src/methodical/impl/dispatcher/everything.clj index 8c20cda..4d7c860 100644 --- a/src/methodical/impl/dispatcher/everything.clj +++ b/src/methodical/impl/dispatcher/everything.clj @@ -26,31 +26,31 @@ (= prefs (.prefs another)))))) Dispatcher - (dispatch-value [_] nil) - (dispatch-value [_ a] nil) - (dispatch-value [_ a b] nil) - (dispatch-value [_ a b c] nil) - (dispatch-value [_ a b c d] nil) - (dispatch-value [_ a b c d more] nil) - - (matching-primary-methods [_ method-table _] + (dispatchValue [_] nil) + (dispatchValue [_ a] nil) + (dispatchValue [_ a b] nil) + (dispatchValue [_ a b c] nil) + (dispatchValue [_ a b c d] nil) + (dispatchValue [_ a b c d more] nil) + + (matchingPrimaryMethods [_ method-table _] (let [primary-methods (i/primary-methods method-table) comparitor (dispatcher.common/domination-comparitor (var-get hierarchy-var) prefs ::no-dispatch-value)] (map second (sort-by first comparitor primary-methods)))) - (matching-aux-methods [_ method-table _] + (matchingAuxMethods [_ method-table _] (let [aux-methods (i/aux-methods method-table) comparitor (dispatcher.common/domination-comparitor (var-get hierarchy-var) prefs ::no-dispatch-value)] (into {} (for [[qualifier dispatch-value->methods] aux-methods] [qualifier (mapcat second (sort-by first comparitor dispatch-value->methods))])))) - (default-dispatch-value [_] + (defaultDispatchValue [_] nil) (prefers [_] prefs) - (prefer-method [this x y] + (preferMethod [this x y] (let [new-prefs (dispatcher.common/add-preference (partial isa? (var-get hierarchy-var)) prefs x y)] (if (= prefs new-prefs) this diff --git a/src/methodical/impl/dispatcher/standard.clj b/src/methodical/impl/dispatcher/standard.clj index 68b6f39..b84549c 100644 --- a/src/methodical/impl/dispatcher/standard.clj +++ b/src/methodical/impl/dispatcher/standard.clj @@ -111,26 +111,26 @@ (= prefs (.prefs another)))))) Dispatcher - (dispatch-value [_] (dispatch-fn)) - (dispatch-value [_ a] (dispatch-fn a)) - (dispatch-value [_ a b] (dispatch-fn a b)) - (dispatch-value [_ a b c] (dispatch-fn a b c)) - (dispatch-value [_ a b c d] (dispatch-fn a b c d)) - (dispatch-value [_ a b c d more] (apply dispatch-fn a b c d more)) + (dispatchValue [_] (dispatch-fn)) + (dispatchValue [_ a] (dispatch-fn a)) + (dispatchValue [_ a b] (dispatch-fn a b)) + (dispatchValue [_ a b c] (dispatch-fn a b c)) + (dispatchValue [_ a b c d] (dispatch-fn a b c d)) + (dispatchValue [_ a b c d more] (apply dispatch-fn a b c d more)) - (matching-primary-methods [_ method-table dispatch-value] + (matchingPrimaryMethods [_ method-table dispatch-value] (matching-primary-methods (var-get hierarchy-var) prefs default-value method-table dispatch-value)) - (matching-aux-methods [_ method-table dispatch-value] + (matchingAuxMethods [_ method-table dispatch-value] (matching-aux-methods (var-get hierarchy-var) prefs default-value method-table dispatch-value)) - (default-dispatch-value [_] + (defaultDispatchValue [_] default-value) (prefers [_] prefs) - (prefer-method [this x y] + (preferMethod [this x y] (let [new-prefs (dispatcher.common/add-preference (partial isa? (var-get hierarchy-var)) prefs x y)] (if (= prefs new-prefs) this diff --git a/src/methodical/impl/method_table/clojure.clj b/src/methodical/impl/method_table/clojure.clj index c731d77..22de9cf 100644 --- a/src/methodical/impl/method_table/clojure.clj +++ b/src/methodical/impl/method_table/clojure.clj @@ -16,26 +16,26 @@ (= m (.m ^ClojureMethodTable another)))) MethodTable - (primary-methods [_] + (primaryMethods [_] m) - (aux-methods [_] + (auxMethods [_] nil) - (add-primary-method [this dispatch-val method] + (addPrimaryMethod [this dispatch-val method] (let [new-m (assoc m dispatch-val method)] (if (= m new-m) this (ClojureMethodTable. new-m)))) - (remove-primary-method [this dispatch-val] + (removePrimaryMethod [this dispatch-val] (let [new-m (dissoc m dispatch-val)] (if (= m new-m) this (ClojureMethodTable. new-m)))) - (add-aux-method [_ _ _ _] + (addAuxMethod [_ _ _ _] (throw (UnsupportedOperationException. "Clojure-style multimethods do not support auxiliary methods."))) - (remove-aux-method [_ _ _ _] + (removeAuxMethod [_ _ _ _] (throw (UnsupportedOperationException. "Clojure-style multimethods do not support auxiliary methods.")))) diff --git a/src/methodical/impl/method_table/standard.clj b/src/methodical/impl/method_table/standard.clj index 32b7b6d..08cd224 100644 --- a/src/methodical/impl/method_table/standard.clj +++ b/src/methodical/impl/method_table/standard.clj @@ -24,25 +24,25 @@ (= aux (.aux ^StandardMethodTable another)))) MethodTable - (primary-methods [_] + (primaryMethods [_] primary) - (aux-methods [_] + (auxMethods [_] aux) - (add-primary-method [this dispatch-val method] + (addPrimaryMethod [this dispatch-val method] (let [new-primary (assoc primary dispatch-val method)] (if (= primary new-primary) this (StandardMethodTable. new-primary aux)))) - (remove-primary-method [this dispatch-val] + (removePrimaryMethod [this dispatch-val] (let [new-primary (dissoc primary dispatch-val)] (if (= primary new-primary) this (StandardMethodTable. new-primary aux)))) - (add-aux-method [this qualifier dispatch-value method] + (addAuxMethod [this qualifier dispatch-value method] (let [new-aux (update-in aux [qualifier dispatch-value] (fn [existing-methods] (if (contains? (set existing-methods) method) existing-methods @@ -51,7 +51,7 @@ this (StandardMethodTable. primary new-aux)))) - (remove-aux-method [this qualifier dispatch-value method] + (removeAuxMethod [this qualifier dispatch-value method] (let [xforms [(fn [aux] (update-in aux [qualifier dispatch-value] (fn [defined-methods] (remove #(= % method) defined-methods)))) diff --git a/src/methodical/impl/standard.clj b/src/methodical/impl/standard.clj index e214190..80e8600 100644 --- a/src/methodical/impl/standard.clj +++ b/src/methodical/impl/standard.clj @@ -10,22 +10,22 @@ (defn- ^:static invoke-multifn ([^MultiFnImpl impl] - ((effective-method impl (.dispatch-value ^Dispatcher (.dispatcher impl))))) + ((effective-method impl (.dispatchValue ^Dispatcher (.dispatcher impl))))) ([^MultiFnImpl impl a] - ((effective-method impl (.dispatch-value ^Dispatcher (.dispatcher impl) a)) a)) + ((effective-method impl (.dispatchValue ^Dispatcher (.dispatcher impl) a)) a)) ([^MultiFnImpl impl a b] - ((effective-method impl (.dispatch-value ^Dispatcher (.dispatcher impl) a b)) a b)) + ((effective-method impl (.dispatchValue ^Dispatcher (.dispatcher impl) a b)) a b)) ([^MultiFnImpl impl a b c] - ((effective-method impl (.dispatch-value ^Dispatcher (.dispatcher impl) a b c)) a b c)) + ((effective-method impl (.dispatchValue ^Dispatcher (.dispatcher impl) a b c)) a b c)) ([^MultiFnImpl impl a b c d] - ((effective-method impl (.dispatch-value ^Dispatcher (.dispatcher impl) a b c d)) a b c d)) + ((effective-method impl (.dispatchValue ^Dispatcher (.dispatcher impl) a b c d)) a b c d)) ([^MultiFnImpl impl a b c d & more] - (apply (effective-method impl (.dispatch-value ^Dispatcher (.dispatcher impl) a b c d more)) a b c d more))) + (apply (effective-method impl (.dispatchValue ^Dispatcher (.dispatcher impl) a b c d more)) a b c d more))) (p.types/deftype+ StandardMultiFn [^MultiFnImpl impl mta] PrettyPrintable @@ -60,51 +60,51 @@ (i/transform-fn-tail (i/method-combination impl) qualifier fn-tail)) Dispatcher - (dispatch-value [_] - (.dispatch-value ^Dispatcher (.dispatcher impl))) - (dispatch-value [_ a] - (.dispatch-value ^Dispatcher (.dispatcher impl) a)) - (dispatch-value [_ a b] - (.dispatch-value ^Dispatcher (.dispatcher impl) a b)) - (dispatch-value [_ a b c] - (.dispatch-value ^Dispatcher (.dispatcher impl) a b c)) - (dispatch-value [_ a b c d] - (.dispatch-value ^Dispatcher (.dispatcher impl) a b c d)) - (dispatch-value [_ a b c d more] - (.dispatch-value ^Dispatcher (.dispatcher impl) a b c d more)) - - (matching-primary-methods [_ method-table dispatch-value] + (dispatchValue [_] + (.dispatchValue ^Dispatcher (.dispatcher impl))) + (dispatchValue [_ a] + (.dispatchValue ^Dispatcher (.dispatcher impl) a)) + (dispatchValue [_ a b] + (.dispatchValue ^Dispatcher (.dispatcher impl) a b)) + (dispatchValue [_ a b c] + (.dispatchValue ^Dispatcher (.dispatcher impl) a b c)) + (dispatchValue [_ a b c d] + (.dispatchValue ^Dispatcher (.dispatcher impl) a b c d)) + (dispatchValue [_ a b c d more] + (.dispatchValue ^Dispatcher (.dispatcher impl) a b c d more)) + + (matchingPrimaryMethods [_ method-table dispatch-value] (i/matching-primary-methods (.dispatcher impl) method-table dispatch-value)) - (matching-aux-methods [_ method-table dispatch-value] + (matchingAuxMethods [_ method-table dispatch-value] (i/matching-aux-methods (.dispatcher impl) method-table dispatch-value)) - (default-dispatch-value [_] + (defaultDispatchValue [_] (i/default-dispatch-value (.dispatcher impl))) (prefers [_] (i/prefers (.dispatcher impl))) - (prefer-method [this dispatch-val-x dispatch-val-y] + (preferMethod [this dispatch-val-x dispatch-val-y] (i/with-dispatcher this (i/prefer-method (.dispatcher impl) dispatch-val-x dispatch-val-y))) MethodTable - (primary-methods [_] + (primaryMethods [_] (i/primary-methods (i/method-table impl))) - (aux-methods [_] + (auxMethods [_] (i/aux-methods (i/method-table impl))) - (add-primary-method [this dispatch-val method] + (addPrimaryMethod [this dispatch-val method] (i/with-method-table this (i/add-primary-method (i/method-table impl) dispatch-val method))) - (remove-primary-method [this dispatch-val] + (removePrimaryMethod [this dispatch-val] (i/with-method-table this (i/remove-primary-method (i/method-table impl) dispatch-val))) - (add-aux-method [this qualifier dispatch-val method] + (addAuxMethod [this qualifier dispatch-val method] (i/with-method-table this (i/add-aux-method (i/method-table impl) qualifier dispatch-val method))) - (remove-aux-method [this qualifier dispatch-val method] + (removeAuxMethod [this qualifier dispatch-val method] (i/with-method-table this (i/remove-aux-method (i/method-table impl) qualifier dispatch-val method))) MultiFnImpl diff --git a/src/methodical/interface.clj b/src/methodical/interface.clj index c78d696..61b5f83 100644 --- a/src/methodical/interface.clj +++ b/src/methodical/interface.clj @@ -32,76 +32,117 @@ [^MethodCombination method-combination qualifier fn-tail] (.transformFnTail method-combination qualifier fn-tail)) -(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 +(definterface MethodTable + (primaryMethods []) + (auxMethods []) + (addPrimaryMethod [dispatch-value f]) + (removePrimaryMethod [dispatch-value]) + (addAuxMethod [qualifier dispatch-value f]) + (removeAuxMethod [qualifier dispatch-val method])) + +(defn primary-methods + "Get a `dispatch-value -> fn` map of all primary methods assoicated with this method table." + [^MethodTable method-table] + (.primaryMethods method-table)) + +(defn aux-methods + "Get a `qualifier -> dispatch-value -> [fn]` map of all auxiliary methods associated with this method table." + [^MethodTable method-table] + (.auxMethods method-table)) + +(defn add-primary-method + "Set the primary method implementation for `dispatch-value`, replacing it if it already exists." + [^MethodTable method-table dispatch-value f] + (.addPrimaryMethod method-table dispatch-value f)) + +(defn remove-primary-method + "Remove the primary method for `dispatch-value`." + [^MethodTable method-table dispatch-value] + (.removePrimaryMethod method-table dispatch-value)) + +(defn add-aux-method + "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 ") + existing methods for this dispatch value. existing " + [^MethodTable method-table qualifier dispatch-value f] + (.addAuxMethod method-table qualifier dispatch-value f)) - (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 +(defn remove-aux-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 + In the future, I hope to fix this by storing unique indentifiers in the metadata of methods in the map." + [^MethodTable method-table qualifier dispatch-val method] + (.removeAuxMethod method-table qualifier dispatch-val method)) + +(definterface Dispatcher + (dispatchValue []) + (dispatchValue [a]) + (dispatchValue [a b]) + (dispatchValue [a b c]) + (dispatchValue [a b c d]) + (dispatchValue [a b c d more]) + + (matchingPrimaryMethods [method-table dispatch-value]) + (matchingAuxMethods [method-table dispatch-value]) + (defaultDispatchValue []) + (prefers []) + (preferMethod [dispatch-val-x dispatch-val-y])) + +(defn dispatch-value + "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.)" + ([^Dispatcher dispatcher] (.dispatchValue dispatcher)) + ([^Dispatcher dispatcher a] (.dispatchValue dispatcher a)) + ([^Dispatcher dispatcher a b] (.dispatchValue dispatcher a b)) + ([^Dispatcher dispatcher a b c] (.dispatchValue dispatcher a b c)) + ([^Dispatcher dispatcher a b c d] (.dispatchValue dispatcher a b c d)) + ([^Dispatcher dispatcher a b c d more] (.dispatchValue dispatcher a b c d more))) + +(defn matching-primary-methods + "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.")) - + ambiguously specific, replacing ambiguous methods with ones that will throw an Exception when invoked." + [^Dispatcher dispatcher method-table dispatch-value] + (.matchingPrimaryMethods dispatcher method-table dispatch-value)) + +(defn matching-aux-methods + "Return a map of aux method qualifier -> sequence of applicable methods for `dispatch-value`, sorted from + most-specific to least-specific." + [^Dispatcher dispatcher method-table dispatch-value] + (.matchingAuxMethods dispatcher method-table dispatch-value)) + +(defn default-dispatch-value + "Default dispatch value to use if no other dispatch value matches." + [^Dispatcher dispatcher] + (.defaultDispatchValue dispatcher)) + +(defn prefers + "Return a map of preferred dispatch value -> set of other dispatch values." + [^Dispatcher dispatcher] + (.prefers dispatcher)) + +(defn prefer-method + "Prefer `dispatch-val-x` over `dispatch-val-y` for dispatch and method combinations." + [^Dispatcher dispatcher dispatch-val-x dispatch-val-y] + (.preferMethod dispatcher dispatch-val-x dispatch-val-y)) (p.types/definterface+ MultiFnImpl (^methodical.interface.MethodCombination method-combination [multifn] - "Get the method combination associated with this multifn.") + "Get the method combination associated with this multifn.") (^methodical.interface.Dispatcher dispatcher [multifn] - "Get the dispatcher associated with this 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.") + "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.") + "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.") + "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 diff --git a/test/methodical/impl/dispatcher/standard_test.clj b/test/methodical/impl/dispatcher/standard_test.clj index 2502da1..4256bfe 100644 --- a/test/methodical/impl/dispatcher/standard_test.clj +++ b/test/methodical/impl/dispatcher/standard_test.clj @@ -15,8 +15,8 @@ (defn- method-table [primary-methods aux-methods] (reify MethodTable - (primary-methods [_] primary-methods) - (aux-methods [_] aux-methods))) + (primaryMethods [_] primary-methods) + (auxMethods [_] aux-methods))) (def ^:private basic-hierarchy (-> (make-hierarchy) From 8bbbc9e3a271a9ae01483858bd91534494403450 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Thu, 12 Sep 2019 12:00:21 +0400 Subject: [PATCH 3/9] MultiFnImpl interface --- src/methodical/impl/multifn/cached.clj | 10 ++--- src/methodical/impl/multifn/standard.clj | 10 ++--- src/methodical/impl/standard.clj | 14 +++--- src/methodical/interface.clj | 57 ++++++++++++++++-------- 4 files changed, 55 insertions(+), 36 deletions(-) diff --git a/src/methodical/impl/multifn/cached.clj b/src/methodical/impl/multifn/cached.clj index 100780b..919a54a 100644 --- a/src/methodical/impl/multifn/cached.clj +++ b/src/methodical/impl/multifn/cached.clj @@ -17,28 +17,28 @@ (= (class cache) (class (.cache ^CachedMultiFnImpl another))))) MultiFnImpl - (method-combination [_] + (methodCombination [_] (i/method-combination impl)) (dispatcher [_] (.dispatcher impl)) - (with-dispatcher [this new-dispatcher] + (withDispatcher [this new-dispatcher] (let [new-impl (i/with-dispatcher impl new-dispatcher)] (if (= impl new-impl) this (CachedMultiFnImpl. new-impl (i/empty-copy cache))))) - (method-table [_] + (methodTable [_] (i/method-table impl)) - (with-method-table [this new-method-table] + (withMethodTable [this new-method-table] (let [new-impl (i/with-method-table impl new-method-table)] (if (= impl new-impl) this (CachedMultiFnImpl. new-impl (i/empty-copy cache))))) - (effective-method [_ dispatch-value] + (effectiveMethod [_ dispatch-value] (or (.cached-method cache dispatch-value) (let [method (i/effective-method impl dispatch-value)] diff --git a/src/methodical/impl/multifn/standard.clj b/src/methodical/impl/multifn/standard.clj index 2ca8115..841704a 100644 --- a/src/methodical/impl/multifn/standard.clj +++ b/src/methodical/impl/multifn/standard.clj @@ -29,24 +29,24 @@ (= method-table (.method-table another)))))) MultiFnImpl - (method-combination [_] + (methodCombination [_] combo) (dispatcher [_] dispatcher) - (with-dispatcher [this new-dispatcher] + (withDispatcher [this new-dispatcher] (if (= dispatcher new-dispatcher) this (StandardMultiFnImpl. combo new-dispatcher method-table))) - (method-table [_] + (methodTable [_] method-table) - (with-method-table [this new-method-table] + (withMethodTable [this new-method-table] (if (= method-table new-method-table) this (StandardMultiFnImpl. combo dispatcher new-method-table))) - (effective-method [_ dispatch-value] + (effectiveMethod [_ dispatch-value] (standard-effective-method combo dispatcher method-table dispatch-value))) diff --git a/src/methodical/impl/standard.clj b/src/methodical/impl/standard.clj index 80e8600..1fa1f7d 100644 --- a/src/methodical/impl/standard.clj +++ b/src/methodical/impl/standard.clj @@ -5,7 +5,7 @@ (:import [methodical.interface Dispatcher MethodCombination MethodTable MultiFnImpl])) (defn- ^:static effective-method [^MultiFnImpl impl, dispatch-value] - (or (.effective-method impl dispatch-value) + (or (.effectiveMethod impl dispatch-value) (throw (UnsupportedOperationException. (format "No matching method for dispatch value %s" dispatch-value))))) (defn- ^:static invoke-multifn @@ -108,29 +108,29 @@ (i/with-method-table this (i/remove-aux-method (i/method-table impl) qualifier dispatch-val method))) MultiFnImpl - (method-combination [_] + (methodCombination [_] (i/method-combination impl)) (dispatcher [_] (.dispatcher impl)) - (with-dispatcher [this new-dispatcher] + (withDispatcher [this new-dispatcher] (assert (instance? Dispatcher new-dispatcher)) (if (= (.dispatcher impl) new-dispatcher) this (StandardMultiFn. (i/with-dispatcher impl new-dispatcher) mta))) - (method-table [_] + (methodTable [_] (i/method-table impl)) - (with-method-table [this new-method-table] + (withMethodTable [this new-method-table] (assert (instance? MethodTable new-method-table)) (if (= (i/method-table impl) new-method-table) this (StandardMultiFn. (i/with-method-table impl new-method-table) mta))) - (effective-method [_ dispatch-value] - (.effective-method impl dispatch-value)) + (effectiveMethod [_ dispatch-value] + (.effectiveMethod impl dispatch-value)) java.util.concurrent.Callable (call [_] diff --git a/src/methodical/interface.clj b/src/methodical/interface.clj index 61b5f83..0e78f4b 100644 --- a/src/methodical/interface.clj +++ b/src/methodical/interface.clj @@ -128,27 +128,46 @@ [^Dispatcher dispatcher dispatch-val-x dispatch-val-y] (.preferMethod dispatcher dispatch-val-x dispatch-val-y)) -(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 +(definterface MultiFnImpl + (^methodical.interface.MethodCombination methodCombination []) + (^methodical.interface.Dispatcher dispatcher []) + (^methodical.interface.MultiFnImpl withDispatcher [new-dispatcher]) + (^methodical.interface.MethodTable methodTable []) + (^methodical.interface.MultiFnImpl withMethodTable [new-method-table]) + (effectiveMethod [dispatch-value])) + +(defn ^methodical.interface.MethodCombination method-combination + "Get the method combination associated with this multifn." + [^MultiFnImpl multifn] + (.methodCombination multifn)) + +(defn ^methodical.interface.Dispatcher dispatcher + "Get the dispatcher associated with this multifn." + [^MultiFnImpl multifn] + (.dispatcher multifn)) + +(defn ^methodical.interface.MultiFnImpl with-dispatcher + "Return a copy of this multifn using `new-dispatcher` as its dispatcher." + [^MultiFnImpl multifn new-dispatcher] + (.withDispatcher multifn new-dispatcher)) + +(defn ^methodical.interface.MethodTable method-table + "Get the method table associated with this multifn." + [^MultiFnImpl multifn] + (.methodTable multifn)) + +(defn ^methodical.interface.MultiFnImpl with-method-table + "Return a copy of this multifn using `new-method-table` as its method table." + [^MultiFnImpl multifn new-method-table] + (.withMethodTable multifn new-method-table)) + +(defn effective-method + "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.")) + be ambiguous with regards to whether it returns only a primary method or a combined effective method." + [^MultiFnImpl multifn dispatch-value] + (.effectiveMethod multifn dispatch-value)) (p.types/definterface+ Cache (cached-method [cache dispatch-value] From 771245ca25d3f96ba83debbd2d91ee31964fea64 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Thu, 12 Sep 2019 12:07:58 +0400 Subject: [PATCH 4/9] Cache interface. --- src/methodical/impl/cache/simple.clj | 8 ++--- src/methodical/impl/cache/watching.clj | 14 ++++---- src/methodical/impl/multifn/cached.clj | 2 +- src/methodical/interface.clj | 37 +++++++++++++------- test/methodical/impl/cache/watching_test.clj | 2 +- 5 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/methodical/impl/cache/simple.clj b/src/methodical/impl/cache/simple.clj index 4a35a19..8b01830 100644 --- a/src/methodical/impl/cache/simple.clj +++ b/src/methodical/impl/cache/simple.clj @@ -12,15 +12,15 @@ '(simple-cache)) Cache - (cached-method [_ dispatch-value] + (cachedMethod [_ dispatch-value] (get @atomm dispatch-value)) - (cache-method! [_ dispatch-value method] + (cacheMethodBang [_ dispatch-value method] (swap! atomm assoc dispatch-value method)) - (clear-cache! [this] + (clearCacheBang [this] (reset! atomm {}) this) - (empty-copy [this] + (emptyCopy [this] (SimpleCache. (atom {})))) diff --git a/src/methodical/impl/cache/watching.clj b/src/methodical/impl/cache/watching.clj index 7b7995f..3574193 100644 --- a/src/methodical/impl/cache/watching.clj +++ b/src/methodical/impl/cache/watching.clj @@ -29,18 +29,18 @@ (remove-watches this)) Cache - (cached-method [_ dispatch-value] - (.cached-method cache dispatch-value)) + (cachedMethod [_ dispatch-value] + (.cachedMethod cache dispatch-value)) - (cache-method! [this dispatch-value method] - (.cache-method! cache dispatch-value method) + (cacheMethodBang [this dispatch-value method] + (.cacheMethodBang cache dispatch-value method) this) - (clear-cache! [this] - (.clear-cache! cache) + (clearCacheBang [this] + (.clearCacheBang cache) this) - (empty-copy [this] + (emptyCopy [this] (add-watches (i/empty-copy cache) refs))) (defn- cache-watch-fn [cache] diff --git a/src/methodical/impl/multifn/cached.clj b/src/methodical/impl/multifn/cached.clj index 919a54a..4ae058a 100644 --- a/src/methodical/impl/multifn/cached.clj +++ b/src/methodical/impl/multifn/cached.clj @@ -40,7 +40,7 @@ (effectiveMethod [_ dispatch-value] (or - (.cached-method cache dispatch-value) + (.cachedMethod cache dispatch-value) (let [method (i/effective-method impl dispatch-value)] (i/cache-method! cache dispatch-value method) method)))) diff --git a/src/methodical/interface.clj b/src/methodical/interface.clj index 0e78f4b..ed16568 100644 --- a/src/methodical/interface.clj +++ b/src/methodical/interface.clj @@ -169,15 +169,28 @@ [^MultiFnImpl multifn dispatch-value] (.effectiveMethod multifn dispatch-value)) -(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.")) +(definterface Cache + (cachedMethod [dispatch-value]) + (cacheMethodBang [dispatch-value method]) + (clearCacheBang []) + (^methodical.interface.Cache emptyCopy [])) + +(defn cached-method + "Return cached effective method for `dispatch-value`, if it exists in the cache." + [^Cache cache dispatch-value] + (.cachedMethod cache dispatch-value)) + +(defn cache-method! + "Cache the effective method for `dispatch-value` in this cache." + [^Cache cache dispatch-value method] + (.cacheMethodBang cache dispatch-value method)) + +(defn clear-cache! + "Empty the contents of the cache in-place." + [^Cache cache] + (.clearCacheBang cache)) + +(defn ^methodical.interface.Cache empty-copy + "Return an empty copy of the same type as this cache, e.g. for use when copying a multifn." + [^Cache cache] + (.emptyCopy cache)) diff --git a/test/methodical/impl/cache/watching_test.clj b/test/methodical/impl/cache/watching_test.clj index c50ca26..7027269 100644 --- a/test/methodical/impl/cache/watching_test.clj +++ b/test/methodical/impl/cache/watching_test.clj @@ -9,7 +9,7 @@ [& [num-times-cleared]] (reify Cache - (clear-cache! [_] + (clearCacheBang [_] (some-> num-times-cleared (swap! inc))) PrettyPrintable From 9a80850d99c40e38a0c9dcf15a26590cf12dd6ae Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Thu, 12 Sep 2019 21:40:25 +0400 Subject: [PATCH 5/9] remove unused ns --- src/methodical/interface.clj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/methodical/interface.clj b/src/methodical/interface.clj index ed16568..a8f6b91 100644 --- a/src/methodical/interface.clj +++ b/src/methodical/interface.clj @@ -1,6 +1,5 @@ (ns methodical.interface - (:refer-clojure :exclude [isa? prefers prefer-method]) - (:require [potemkin.types :as p.types])) + (:refer-clojure :exclude [isa? prefers prefer-method])) (definterface MethodCombination (allowedQualifiers []) From 3135be913be99d9232481405c90a9a2035055f35 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Thu, 12 Sep 2019 21:57:15 +0400 Subject: [PATCH 6/9] deftype+ => deftype --- src/methodical/impl/cache/simple.clj | 5 ++--- src/methodical/impl/cache/watching.clj | 3 +-- src/methodical/impl/combo/clojure.clj | 5 ++--- src/methodical/impl/combo/clos.clj | 3 +-- src/methodical/impl/combo/operator.clj | 3 +-- src/methodical/impl/combo/threaded.clj | 3 +-- src/methodical/impl/dispatcher/everything.clj | 3 +-- src/methodical/impl/dispatcher/standard.clj | 3 +-- src/methodical/impl/method_table/clojure.clj | 5 ++--- src/methodical/impl/method_table/standard.clj | 5 ++--- src/methodical/impl/multifn/cached.clj | 3 +-- src/methodical/impl/multifn/standard.clj | 7 +++---- src/methodical/impl/standard.clj | 3 +-- 13 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/methodical/impl/cache/simple.clj b/src/methodical/impl/cache/simple.clj index 8b01830..a10b961 100644 --- a/src/methodical/impl/cache/simple.clj +++ b/src/methodical/impl/cache/simple.clj @@ -2,11 +2,10 @@ "A basic, dumb cache. `SimpleCache` stores cached methods in a simple map of dispatch-value -> effective method; it offers no facilities to deduplicate identical methods for the same dispatch value. This behaves similarly to the caching mechanism in vanilla Clojure." - (:require [potemkin.types :as p.types] - [pretty.core :refer [PrettyPrintable]]) + (:require [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.Cache)) -(p.types/deftype+ SimpleCache [atomm] +(deftype SimpleCache [atomm] PrettyPrintable (pretty [_] '(simple-cache)) diff --git a/src/methodical/impl/cache/watching.clj b/src/methodical/impl/cache/watching.clj index 3574193..3634b93 100644 --- a/src/methodical/impl/cache/watching.clj +++ b/src/methodical/impl/cache/watching.clj @@ -12,14 +12,13 @@ finalized (which, of course, may actually be never -- but worst-case is that some unneeded calls to `clear-cache!` get made)." (:require [methodical.interface :as i] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import java.lang.ref.WeakReference methodical.interface.Cache)) (declare add-watches remove-watches) -(p.types/deftype+ WatchingCache [^Cache cache watch-key refs] +(deftype WatchingCache [^Cache cache watch-key refs] PrettyPrintable (pretty [_] (concat ['watching-cache cache 'watching] refs)) diff --git a/src/methodical/impl/combo/clojure.clj b/src/methodical/impl/combo/clojure.clj index b1b1c18..d528d36 100644 --- a/src/methodical/impl/combo/clojure.clj +++ b/src/methodical/impl/combo/clojure.clj @@ -1,11 +1,10 @@ (ns methodical.impl.combo.clojure "Simple method combination strategy that mimics the way vanilla Clojure multimethods combine methods; that is, to say, not at all. Like vanilla Clojure multimethods, this method combination only supports primary methods." - (:require [potemkin.types :as p.types] - [pretty.core :refer [PrettyPrintable]]) + (:require [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.MethodCombination)) -(p.types/deftype+ ClojureMethodCombination [] +(deftype ClojureMethodCombination [] PrettyPrintable (pretty [_] '(clojure-method-combination)) diff --git a/src/methodical/impl/combo/clos.clj b/src/methodical/impl/combo/clos.clj index 7e39221..b9be6aa 100644 --- a/src/methodical/impl/combo/clos.clj +++ b/src/methodical/impl/combo/clos.clj @@ -4,7 +4,6 @@ are ignored. Primary methods and around methods get an implicit `next-method` arg (see Methodical dox for more on what this means)." (:require [methodical.impl.combo.common :as combo.common] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.MethodCombination)) @@ -53,7 +52,7 @@ result)] (comp apply-afters combined-method)))) -(p.types/deftype+ CLOSStandardMethodCombination [] +(deftype CLOSStandardMethodCombination [] PrettyPrintable (pretty [_] '(clos-method-combination)) diff --git a/src/methodical/impl/combo/operator.clj b/src/methodical/impl/combo/operator.clj index 67eb401..7d37612 100644 --- a/src/methodical/impl/combo/operator.clj +++ b/src/methodical/impl/combo/operator.clj @@ -38,7 +38,6 @@ ...)" (:refer-clojure :exclude [methods]) (:require [methodical.impl.combo.common :as combo.common] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.MethodCombination)) @@ -152,7 +151,7 @@ ;;;; ### `OperatorMethodCombination` -(p.types/deftype+ OperatorMethodCombination [operator-name] +(deftype OperatorMethodCombination [operator-name] PrettyPrintable (pretty [_] (list 'operator-method-combination operator-name)) diff --git a/src/methodical/impl/combo/threaded.clj b/src/methodical/impl/combo/threaded.clj index 54942e5..3a2e227 100644 --- a/src/methodical/impl/combo/threaded.clj +++ b/src/methodical/impl/combo/threaded.clj @@ -1,7 +1,6 @@ (ns methodical.impl.combo.threaded (:refer-clojure :exclude [methods]) (:require [methodical.impl.combo.common :as combo.common] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.MethodCombination)) @@ -70,7 +69,7 @@ (apply method (conj butlast* last*)))])))) -(p.types/deftype+ ThreadingMethodCombination [threading-type] +(deftype ThreadingMethodCombination [threading-type] PrettyPrintable (pretty [_] (list 'threading-method-combination threading-type)) diff --git a/src/methodical/impl/dispatcher/everything.clj b/src/methodical/impl/dispatcher/everything.clj index 4d7c860..0f23a18 100644 --- a/src/methodical/impl/dispatcher/everything.clj +++ b/src/methodical/impl/dispatcher/everything.clj @@ -1,11 +1,10 @@ (ns methodical.impl.dispatcher.everything (:require [methodical.impl.dispatcher.common :as dispatcher.common] [methodical.interface :as i] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.Dispatcher)) -(p.types/deftype+ EverythingDispatcher [hierarchy-var prefs] +(deftype EverythingDispatcher [hierarchy-var prefs] PrettyPrintable (pretty [_] (cons diff --git a/src/methodical/impl/dispatcher/standard.clj b/src/methodical/impl/dispatcher/standard.clj index b84549c..a33464f 100644 --- a/src/methodical/impl/dispatcher/standard.clj +++ b/src/methodical/impl/dispatcher/standard.clj @@ -4,7 +4,6 @@ (:refer-clojure :exclude [prefers prefer-method]) (:require [methodical.impl.dispatcher.common :as dispatcher.common] [methodical.interface :as i] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.Dispatcher)) @@ -88,7 +87,7 @@ [qualifier (map second pairs)]))) -(p.types/deftype+ StandardDispatcher [dispatch-fn hierarchy-var default-value prefs] +(deftype StandardDispatcher [dispatch-fn hierarchy-var default-value prefs] PrettyPrintable (pretty [_] (concat ['standard-dispatcher dispatch-fn] diff --git a/src/methodical/impl/method_table/clojure.clj b/src/methodical/impl/method_table/clojure.clj index 22de9cf..7ff0d4b 100644 --- a/src/methodical/impl/method_table/clojure.clj +++ b/src/methodical/impl/method_table/clojure.clj @@ -1,9 +1,8 @@ (ns methodical.impl.method-table.clojure - (:require [potemkin.types :as p.types] - [pretty.core :refer [PrettyPrintable]]) + (:require [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.MethodTable)) -(p.types/deftype+ ClojureMethodTable [m] +(deftype ClojureMethodTable [m] PrettyPrintable (pretty [_] (if (seq m) diff --git a/src/methodical/impl/method_table/standard.clj b/src/methodical/impl/method_table/standard.clj index 08cd224..43dedac 100644 --- a/src/methodical/impl/method_table/standard.clj +++ b/src/methodical/impl/method_table/standard.clj @@ -1,9 +1,8 @@ (ns methodical.impl.method-table.standard - (:require [potemkin.types :as p.types] - [pretty.core :refer [PrettyPrintable]]) + (:require [pretty.core :refer [PrettyPrintable]]) (:import methodical.interface.MethodTable)) -(p.types/deftype+ StandardMethodTable [primary aux] +(deftype StandardMethodTable [primary aux] PrettyPrintable (pretty [_] (cons diff --git a/src/methodical/impl/multifn/cached.clj b/src/methodical/impl/multifn/cached.clj index 4ae058a..ca2bfcc 100644 --- a/src/methodical/impl/multifn/cached.clj +++ b/src/methodical/impl/multifn/cached.clj @@ -1,10 +1,9 @@ (ns methodical.impl.multifn.cached (:require [methodical.interface :as i] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import [methodical.interface Cache MultiFnImpl])) -(p.types/deftype+ CachedMultiFnImpl [^MultiFnImpl impl, ^Cache cache] +(deftype CachedMultiFnImpl [^MultiFnImpl impl, ^Cache cache] PrettyPrintable (pretty [_] (list 'cached-multifn-impl impl cache)) diff --git a/src/methodical/impl/multifn/standard.clj b/src/methodical/impl/multifn/standard.clj index 841704a..c6e7132 100644 --- a/src/methodical/impl/multifn/standard.clj +++ b/src/methodical/impl/multifn/standard.clj @@ -1,7 +1,6 @@ (ns methodical.impl.multifn.standard "Standard Methodical MultiFn impl, which " (:require [methodical.interface :as i] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import [methodical.interface Dispatcher MethodCombination MethodTable MultiFnImpl])) @@ -13,9 +12,9 @@ aux-methods (i/matching-aux-methods dispatcher method-table dispatch-value)] (i/combine-methods method-combination primary-methods aux-methods))) -(p.types/deftype+ StandardMultiFnImpl [^MethodCombination combo - ^Dispatcher dispatcher - ^MethodTable method-table] +(deftype StandardMultiFnImpl [^MethodCombination combo + ^Dispatcher dispatcher + ^MethodTable method-table] PrettyPrintable (pretty [_] (list 'standard-multifn-impl combo dispatcher method-table)) diff --git a/src/methodical/impl/standard.clj b/src/methodical/impl/standard.clj index 1fa1f7d..ff94a0a 100644 --- a/src/methodical/impl/standard.clj +++ b/src/methodical/impl/standard.clj @@ -1,6 +1,5 @@ (ns methodical.impl.standard (:require [methodical.interface :as i] - [potemkin.types :as p.types] [pretty.core :refer [PrettyPrintable]]) (:import [methodical.interface Dispatcher MethodCombination MethodTable MultiFnImpl])) @@ -27,7 +26,7 @@ ([^MultiFnImpl impl a b c d & more] (apply (effective-method impl (.dispatchValue ^Dispatcher (.dispatcher impl) a b c d more)) a b c d more))) -(p.types/deftype+ StandardMultiFn [^MultiFnImpl impl mta] +(deftype StandardMultiFn [^MultiFnImpl impl mta] PrettyPrintable (pretty [_] (list 'multifn impl)) From cd832072bc198b065c6b2ca4605c36d60bb2ebfd Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Fri, 13 Sep 2019 09:41:05 +0400 Subject: [PATCH 7/9] defonceinterface --- src/methodical/interface.clj | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/methodical/interface.clj b/src/methodical/interface.clj index a8f6b91..02a0f66 100644 --- a/src/methodical/interface.clj +++ b/src/methodical/interface.clj @@ -1,7 +1,20 @@ (ns methodical.interface (:refer-clojure :exclude [isa? prefers prefer-method])) -(definterface MethodCombination +(defmacro ^:private defonceinterface [name & body] + (let [class-name (clojure.string/replace (str *ns* "." name) #"\-" "_") + exists (try + (Class/forName class-name) + true + (catch Exception _ + false))] + (if exists + `(do + (import ~(symbol class-name)) + nil) + `(definterface ~name ~@body)))) + +(defonceinterface MethodCombination (allowedQualifiers []) (combineMethods [primary-methods aux-methods]) (transformFnTail [qualifier fn-tail])) @@ -31,7 +44,7 @@ [^MethodCombination method-combination qualifier fn-tail] (.transformFnTail method-combination qualifier fn-tail)) -(definterface MethodTable +(defonceinterface MethodTable (primaryMethods []) (auxMethods []) (addPrimaryMethod [dispatch-value f]) @@ -75,7 +88,7 @@ [^MethodTable method-table qualifier dispatch-val method] (.removeAuxMethod method-table qualifier dispatch-val method)) -(definterface Dispatcher +(defonceinterface Dispatcher (dispatchValue []) (dispatchValue [a]) (dispatchValue [a b]) @@ -127,7 +140,7 @@ [^Dispatcher dispatcher dispatch-val-x dispatch-val-y] (.preferMethod dispatcher dispatch-val-x dispatch-val-y)) -(definterface MultiFnImpl +(defonceinterface MultiFnImpl (^methodical.interface.MethodCombination methodCombination []) (^methodical.interface.Dispatcher dispatcher []) (^methodical.interface.MultiFnImpl withDispatcher [new-dispatcher]) @@ -168,7 +181,7 @@ [^MultiFnImpl multifn dispatch-value] (.effectiveMethod multifn dispatch-value)) -(definterface Cache +(defonceinterface Cache (cachedMethod [dispatch-value]) (cacheMethodBang [dispatch-value method]) (clearCacheBang []) From 2f86cdde1b9cbe377cecfaeea31f4e2273030ae9 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Fri, 13 Sep 2019 09:48:21 +0400 Subject: [PATCH 8/9] fix name --- src/methodical/interface.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/methodical/interface.clj b/src/methodical/interface.clj index 02a0f66..44da355 100644 --- a/src/methodical/interface.clj +++ b/src/methodical/interface.clj @@ -1,8 +1,8 @@ (ns methodical.interface (:refer-clojure :exclude [isa? prefers prefer-method])) -(defmacro ^:private defonceinterface [name & body] - (let [class-name (clojure.string/replace (str *ns* "." name) #"\-" "_") +(defmacro ^:private defonceinterface [interface-name & body] + (let [class-name (clojure.string/replace (str *ns* "." interface-name) #"\-" "_") exists (try (Class/forName class-name) true @@ -12,7 +12,7 @@ `(do (import ~(symbol class-name)) nil) - `(definterface ~name ~@body)))) + `(definterface ~interface-name ~@body)))) (defonceinterface MethodCombination (allowedQualifiers []) From 7ebbd0b1fcb264e5c42d681b5d23959f1e235314 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Sat, 21 Sep 2019 16:02:46 +0400 Subject: [PATCH 9/9] some cljc --- .gitignore | 1 + project.clj | 3 +- .../dispatcher/{common.clj => common.cljc} | 7 +- .../{standard.clj => standard.cljc} | 41 ++++--- .../{interface.clj => interface.cljc} | 114 ++++++++++-------- 5 files changed, 99 insertions(+), 67 deletions(-) rename src/methodical/impl/dispatcher/{common.clj => common.cljc} (93%) rename src/methodical/impl/dispatcher/{standard.clj => standard.cljc} (86%) rename src/methodical/{interface.clj => interface.cljc} (77%) diff --git a/.gitignore b/.gitignore index 8997057..19b0d19 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ /tags /target \#*\# +/.cljs_node_repl diff --git a/project.clj b/project.clj index 4c10400..1cfc72f 100644 --- a/project.clj +++ b/project.clj @@ -27,7 +27,8 @@ :dependencies [[pretty "1.0.0"] - [potemkin "0.4.5"]] + [potemkin "0.4.5"] + [org.clojure/clojurescript "1.10.520" :scope "provided"]] :aot [methodical.interface methodical.impl.standard] diff --git a/src/methodical/impl/dispatcher/common.clj b/src/methodical/impl/dispatcher/common.cljc similarity index 93% rename from src/methodical/impl/dispatcher/common.clj rename to src/methodical/impl/dispatcher/common.cljc index 08a1938..c2871c3 100644 --- a/src/methodical/impl/dispatcher/common.clj +++ b/src/methodical/impl/dispatcher/common.cljc @@ -1,5 +1,10 @@ (ns methodical.impl.dispatcher.common - "Utility functions for implementing Dispatchers.") + "Utility functions for implementing Dispatchers." + #?(:cljs + (:require + [goog.string :refer [format]]))) + +#?(:cljs (def ^:private IllegalStateException js/Error)) (defn add-preference "Add a method preference to `prefs` for dispatch value `x` over `y`. Used to implement `prefer-method`." diff --git a/src/methodical/impl/dispatcher/standard.clj b/src/methodical/impl/dispatcher/standard.cljc similarity index 86% rename from src/methodical/impl/dispatcher/standard.clj rename to src/methodical/impl/dispatcher/standard.cljc index a33464f..7d46a2f 100644 --- a/src/methodical/impl/dispatcher/standard.clj +++ b/src/methodical/impl/dispatcher/standard.cljc @@ -4,8 +4,12 @@ (:refer-clojure :exclude [prefers prefer-method]) (:require [methodical.impl.dispatcher.common :as dispatcher.common] [methodical.interface :as i] - [pretty.core :refer [PrettyPrintable]]) - (:import methodical.interface.Dispatcher)) + #?(:clj [pretty.core :refer [PrettyPrintable]]) + #?(:cljs [methodical.interface :refer [Dispatcher]]) + #?(:cljs [goog.string :refer [format]])) + #?(:clj (:import methodical.interface.Dispatcher))) + +#?(:cljs (def ^:private IllegalArgumentException js/Error)) (defn- matching-primary-pairs-excluding-default "Return a sequence of pairs of `[dispatch-value method]` for all applicable dispatch values, excluding the default @@ -86,20 +90,23 @@ :when (seq pairs)] [qualifier (map second pairs)]))) - (deftype StandardDispatcher [dispatch-fn hierarchy-var default-value prefs] - PrettyPrintable - (pretty [_] - (concat ['standard-dispatcher dispatch-fn] - (when (not= hierarchy-var #'clojure.core/global-hierarchy) - [:hierarchy hierarchy-var]) - (when (not= default-value :default) - [:default-value default-value]) - (when (seq prefs) - [:prefers prefs]))) - - Object - (equals [_ another] + #?@(:clj + [PrettyPrintable + (pretty [_] + (concat ['standard-dispatcher dispatch-fn] + (when (not= hierarchy-var #'clojure.core/global-hierarchy) + [:hierarchy hierarchy-var]) + (when (not= default-value :default) + [:default-value default-value]) + (when (seq prefs) + [:prefers prefs])))]) + + #?(:clj Object + :cljs IEquiv) + ;; todo: hashcode + + (#?(:clj equals, :cljs -equiv) [_ another] (and (instance? StandardDispatcher another) (let [^StandardDispatcher another another] @@ -109,7 +116,7 @@ (= default-value (.default-value another)) (= prefs (.prefs another)))))) - Dispatcher + #?(:clj Dispatcher :cljs Object) (dispatchValue [_] (dispatch-fn)) (dispatchValue [_ a] (dispatch-fn a)) (dispatchValue [_ a b] (dispatch-fn a b)) @@ -130,6 +137,8 @@ prefs) (preferMethod [this x y] + ;; var-get is not implemented in cljs + ;; https://github.com/camsaul/methodical/issues/29 (let [new-prefs (dispatcher.common/add-preference (partial isa? (var-get hierarchy-var)) prefs x y)] (if (= prefs new-prefs) this diff --git a/src/methodical/interface.clj b/src/methodical/interface.cljc similarity index 77% rename from src/methodical/interface.clj rename to src/methodical/interface.cljc index 44da355..17ae55e 100644 --- a/src/methodical/interface.clj +++ b/src/methodical/interface.cljc @@ -1,23 +1,27 @@ (ns methodical.interface (:refer-clojure :exclude [isa? prefers prefer-method])) -(defmacro ^:private defonceinterface [interface-name & body] - (let [class-name (clojure.string/replace (str *ns* "." interface-name) #"\-" "_") - exists (try - (Class/forName class-name) - true - (catch Exception _ - false))] - (if exists - `(do - (import ~(symbol class-name)) - nil) - `(definterface ~interface-name ~@body)))) - -(defonceinterface MethodCombination - (allowedQualifiers []) - (combineMethods [primary-methods aux-methods]) - (transformFnTail [qualifier fn-tail])) +#?(:clj + (defmacro ^:private defonceinterface [interface-name & body] + (let [class-name (clojure.string/replace (str *ns* "." interface-name) #"\-" "_") + exists (try + (Class/forName class-name) + true + (catch Exception _ + false))] + (if exists + `(do + (import ~(symbol class-name)) + nil) + `(definterface ~interface-name ~@body))))) + +#?(:clj + (defonceinterface MethodCombination + (allowedQualifiers []) + (combineMethods [primary-methods aux-methods]) + (transformFnTail [qualifier fn-tail])) + :cljs + (def MethodCombination)) (defn allowed-qualifiers "The set containg all qualifiers supported by this method combination. `nil` in the set means the method @@ -44,13 +48,16 @@ [^MethodCombination method-combination qualifier fn-tail] (.transformFnTail method-combination qualifier fn-tail)) -(defonceinterface MethodTable - (primaryMethods []) - (auxMethods []) - (addPrimaryMethod [dispatch-value f]) - (removePrimaryMethod [dispatch-value]) - (addAuxMethod [qualifier dispatch-value f]) - (removeAuxMethod [qualifier dispatch-val method])) +#?(:clj + (defonceinterface MethodTable + (primaryMethods []) + (auxMethods []) + (addPrimaryMethod [dispatch-value f]) + (removePrimaryMethod [dispatch-value]) + (addAuxMethod [qualifier dispatch-value f]) + (removeAuxMethod [qualifier dispatch-val method])) + :cljs + (def MethodTable)) (defn primary-methods "Get a `dispatch-value -> fn` map of all primary methods assoicated with this method table." @@ -88,19 +95,22 @@ [^MethodTable method-table qualifier dispatch-val method] (.removeAuxMethod method-table qualifier dispatch-val method)) -(defonceinterface Dispatcher - (dispatchValue []) - (dispatchValue [a]) - (dispatchValue [a b]) - (dispatchValue [a b c]) - (dispatchValue [a b c d]) - (dispatchValue [a b c d more]) - - (matchingPrimaryMethods [method-table dispatch-value]) - (matchingAuxMethods [method-table dispatch-value]) - (defaultDispatchValue []) - (prefers []) - (preferMethod [dispatch-val-x dispatch-val-y])) +#?(:clj + (defonceinterface Dispatcher + (dispatchValue []) + (dispatchValue [a]) + (dispatchValue [a b]) + (dispatchValue [a b c]) + (dispatchValue [a b c d]) + (dispatchValue [a b c d more]) + + (matchingPrimaryMethods [method-table dispatch-value]) + (matchingAuxMethods [method-table dispatch-value]) + (defaultDispatchValue []) + (prefers []) + (preferMethod [dispatch-val-x dispatch-val-y])) + :cljs + (def Dispatcher)) (defn dispatch-value "Return an appropriate dispatch value for args passed to a multimethod. (This method is equivalent in purpose to @@ -140,13 +150,16 @@ [^Dispatcher dispatcher dispatch-val-x dispatch-val-y] (.preferMethod dispatcher dispatch-val-x dispatch-val-y)) -(defonceinterface MultiFnImpl - (^methodical.interface.MethodCombination methodCombination []) - (^methodical.interface.Dispatcher dispatcher []) - (^methodical.interface.MultiFnImpl withDispatcher [new-dispatcher]) - (^methodical.interface.MethodTable methodTable []) - (^methodical.interface.MultiFnImpl withMethodTable [new-method-table]) - (effectiveMethod [dispatch-value])) +#?(:clj + (defonceinterface MultiFnImpl + (^methodical.interface.MethodCombination methodCombination []) + (^methodical.interface.Dispatcher dispatcher []) + (^methodical.interface.MultiFnImpl withDispatcher [new-dispatcher]) + (^methodical.interface.MethodTable methodTable []) + (^methodical.interface.MultiFnImpl withMethodTable [new-method-table]) + (effectiveMethod [dispatch-value])) + :cljs + (def MultiFnImpl)) (defn ^methodical.interface.MethodCombination method-combination "Get the method combination associated with this multifn." @@ -181,11 +194,14 @@ [^MultiFnImpl multifn dispatch-value] (.effectiveMethod multifn dispatch-value)) -(defonceinterface Cache - (cachedMethod [dispatch-value]) - (cacheMethodBang [dispatch-value method]) - (clearCacheBang []) - (^methodical.interface.Cache emptyCopy [])) +#?(:clj + (defonceinterface Cache + (cachedMethod [dispatch-value]) + (cacheMethodBang [dispatch-value method]) + (clearCacheBang []) + (^methodical.interface.Cache emptyCopy [])) + :cljs + (def Cache)) (defn cached-method "Return cached effective method for `dispatch-value`, if it exists in the cache."