diff options
author | Rich Hickey <richhickey@gmail.com> | 2007-10-20 20:09:54 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2007-10-20 20:09:54 +0000 |
commit | fe567065b55b47705a6292e6f993001e4ef31997 (patch) | |
tree | 15e20f261c9844d1944dbfa56f33d08789d29fe0 /src | |
parent | 068bc4439d03127b78cf223504a626dbd05e6b04 (diff) |
Multimethods
Diffstat (limited to 'src')
-rw-r--r-- | src/boot.clj | 24 | ||||
-rw-r--r-- | src/jvm/clojure/lang/MultiFn.java | 27 |
2 files changed, 27 insertions, 24 deletions
diff --git a/src/boot.clj b/src/boot.clj index 012e3a1d..20e7702f 100644 --- a/src/boot.clj +++ b/src/boot.clj @@ -296,14 +296,21 @@ ([x form] `(. ~x ~form)) ([x form & more] `(.. (. ~x ~form) ~@more))) -;;polyfns -(defmacro defpolyfn [name dispatch-fn] - `(def ~name (new clojure.lang.PolyFn ~dispatch-fn))) +;;multimethods +(defmacro defmulti + ([name dispatch-fn] (thisfn name dispatch-fn :default)) + ([name dispatch-fn default-val] + `(def ~name (new clojure.lang.MultiFn ~dispatch-fn ~default-val)))) -(defmacro defmethod [polyfn dispatch-val & fn-tail] - `(let [pvar# (the-var ~polyfn)] - (locking pvar# - (. pvar# (bindRoot (.. pvar# (getRoot) (assoc ~dispatch-val (fn ~@fn-tail)))))))) +(defmacro defmethod [multifn dispatch-val & fn-tail] + `(let [pvar# (the-var ~multifn)] + (. pvar# (commuteRoot (fn [mf#] (. mf# (assoc ~dispatch-val (fn ~@fn-tail)))))))) + +(defmacro remove-method [multifn dispatch-val] + `(let [pvar# (the-var ~multifn)] + (. pvar# (commuteRoot (fn [mf#] (. mf# (dissoc ~dispatch-val))))))) + +;;;;;;;;; var stuff (defmacro binding [bindings & body] (let [var-ize (fn [var-vals] @@ -600,7 +607,8 @@ peek pop nth contains get assoc dissoc find keys vals merge rseq sym name namespace locking .. - defpolyfn defmethod binding find-var + defmulti defmethod remove-method + binding find-var ref deref deref! commute set sync reduce reverse comp appl every not-every any not-any diff --git a/src/jvm/clojure/lang/MultiFn.java b/src/jvm/clojure/lang/MultiFn.java index a122b199..53c0b8d5 100644 --- a/src/jvm/clojure/lang/MultiFn.java +++ b/src/jvm/clojure/lang/MultiFn.java @@ -14,48 +14,43 @@ package clojure.lang; public class MultiFn extends AFn{ final public IFn dispatchFn; -final public IFn defaultFn; +final public Object defaultDispatchVal; final public IPersistentMap methodTable; -public MultiFn(IFn dispatchFn, IFn defaultFn){ +public MultiFn(IFn dispatchFn, Object defaultDispatchVal){ this.dispatchFn = dispatchFn; - this.defaultFn = defaultFn; + this.defaultDispatchVal = defaultDispatchVal; this.methodTable = PersistentHashMap.EMPTY; } public MultiFn assoc(Object dispatchVal, IFn method){ - return new MultiFn(meta(), dispatchFn, defaultFn, methodTable.assoc(dispatchVal, method)); + return new MultiFn(meta(), dispatchFn, defaultDispatchVal, methodTable.assoc(dispatchVal, method)); } -public MultiFn withDefaultFn(IFn newDefaultFn){ - return new MultiFn(meta(), dispatchFn, newDefaultFn, methodTable); -} -public MultiFn without(Object dispatchVal){ - return new MultiFn(meta(), dispatchFn, defaultFn, methodTable.without(dispatchVal)); +public MultiFn dissoc(Object dispatchVal){ + return new MultiFn(meta(), dispatchFn, defaultDispatchVal, methodTable.without(dispatchVal)); } public Obj withMeta(IPersistentMap meta){ if(meta == meta()) return this; - return new MultiFn(meta, dispatchFn, defaultFn, methodTable); + return new MultiFn(meta, dispatchFn, defaultDispatchVal, methodTable); } -private MultiFn(IPersistentMap meta, IFn dispatchFn, IFn defaultFn, IPersistentMap dispatchTable){ +private MultiFn(IPersistentMap meta, IFn dispatchFn, Object defaultDispatchVal, IPersistentMap dispatchTable){ super(meta); this.dispatchFn = dispatchFn; - this.defaultFn = defaultFn; + this.defaultDispatchVal = defaultDispatchVal; this.methodTable = dispatchTable; } private IFn getFn(Object dispatchVal) throws Exception{ IFn targetFn = (IFn) methodTable.valAt(dispatchVal); if(targetFn == null) - { - if(defaultFn != null) - return defaultFn; + targetFn = (IFn) methodTable.valAt(defaultDispatchVal); + if(targetFn == null) throw new IllegalArgumentException(String.format("No method for dispatch value: %s", dispatchVal)); - } return targetFn; } |