diff options
author | Rich Hickey <richhickey@gmail.com> | 2009-10-30 13:23:13 -0400 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2009-10-30 13:23:13 -0400 |
commit | 9c3e97a85c042d2c3f276f0c1e0d270db35553aa (patch) | |
tree | 201bb9c0beea2deed36452f9b9bd870f7bb460e7 /src | |
parent | 1c8e76b1a0e6616c780902a317a7ab9a8423288b (diff) |
methodnames now take form (.methodname [args] body) in reify/deftype/class
Diffstat (limited to 'src')
-rw-r--r-- | src/clj/clojure/core.clj | 16 | ||||
-rw-r--r-- | src/clj/clojure/core_deftype.clj | 58 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 7 |
3 files changed, 46 insertions, 35 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 46a7b233..7d323472 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -4462,12 +4462,12 @@ [#^Callable f] (let [fut (.submit clojure.lang.Agent/soloExecutor f)] (reify [clojure.lang.IDeref java.util.concurrent.Future] - (deref [] (.get fut)) - (get [] (.get fut)) - (get [timeout unit] (.get fut timeout unit)) - (isCancelled [] (.isCancelled fut)) - (isDone [] (.isDone fut)) - (cancel [interrupt?] (.cancel fut interrupt?))))) + (.deref [] (.get fut)) + (.get [] (.get fut)) + (.get [timeout unit] (.get fut timeout unit)) + (.isCancelled [] (.isCancelled fut)) + (.isDone [] (.isDone fut)) + (.cancel [interrupt?] (.cancel fut interrupt?))))) (defmacro future "Takes a body of expressions and yields a future object that will @@ -4565,8 +4565,8 @@ (let [d (java.util.concurrent.CountDownLatch. 1) v (atom nil)] (reify this [clojure.lang.IFn clojure.lang.IDeref] - (deref [] (.await d) @v) - (invoke [x] + (.deref [] (.await d) @v) + (.invoke [x] (locking d (if (pos? (.getCount d)) (do (reset! v x) diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj index 5eae26c3..c778906e 100644 --- a/src/clj/clojure/core_deftype.clj +++ b/src/clj/clojure/core_deftype.clj @@ -29,11 +29,11 @@ fields (conj fields '__meta '__extmap)] (letfn [(eqhash [[i m]] - (if (not (or (contains? methodname-set 'equals) (contains? methodname-set 'hashCode))) + (if (not (or (contains? methodname-set '.equals) (contains? methodname-set '.hashCode))) [i (conj m - `(~'hashCode [] (-> ~tag hash ~@(map #(list `hash-combine %) (remove #{'__meta} fields)))) - `(~'equals [~'o] + `(.hashCode [] (-> ~tag hash ~@(map #(list `hash-combine %) (remove #{'__meta} fields)))) + `(.equals [~'o] (boolean (or (identical? ~'this ~'o) (when (instance? ~name ~'o) @@ -43,40 +43,40 @@ (iobj [[i m]] (if (and (implement? clojure.lang.IObj) (implement? clojure.lang.IMeta)) [(conj i 'clojure.lang.IObj) - (conj m `(~'meta [] ~'__meta) - `(~'withMeta [~'m] (new ~name ~@(replace {'__meta 'm} fields))))] + (conj m `(.meta [] ~'__meta) + `(.withMeta [~'m] (new ~name ~@(replace {'__meta 'm} fields))))] [i m])) (ilookup [[i m]] (if (implement? clojure.lang.ILookup) [(conj i 'clojure.lang.ILookup) - (conj m `(~'valAt [k#] (.valAt ~'this k# nil)) - `(~'valAt [k# else#] + (conj m `(.valAt [k#] (.valAt ~'this k# nil)) + `(.valAt [k# else#] (case k# ~@(mapcat (fn [fld] [(keyword fld) fld]) base-fields) (get ~'__extmap k# else#))))] [i m])) (imap [[i m]] - (if (and (interface-set clojure.lang.IPersistentMap) (not (methodname-set 'assoc))) + (if (and (interface-set clojure.lang.IPersistentMap) (not (methodname-set '.assoc))) [i (conj m - `(~'count [] (+ ~(count base-fields) (count ~'__extmap))) - `(~'empty [] (throw (UnsupportedOperationException. (str "Can't create empty: " ~(str classname))))) - `(~'cons [e#] (let [[k# v#] e#] (.assoc ~'this k# v#))) - `(~'equiv [o#] (.equals ~'this o#)) - `(~'containsKey [k#] (not (identical? ~'this (.valAt ~'this k# ~'this)))) - `(~'entryAt [k#] (let [v# (.valAt ~'this k# ~'this)] + `(.count [] (+ ~(count base-fields) (count ~'__extmap))) + `(.empty [] (throw (UnsupportedOperationException. (str "Can't create empty: " ~(str classname))))) + `(.cons [e#] (let [[k# v#] e#] (.assoc ~'this k# v#))) + `(.equiv [o#] (.equals ~'this o#)) + `(.containsKey [k#] (not (identical? ~'this (.valAt ~'this k# ~'this)))) + `(.entryAt [k#] (let [v# (.valAt ~'this k# ~'this)] (when-not (identical? ~'this v#) (clojure.lang.MapEntry. k# v#)))) - `(~'seq [] (concat [~@(map #(list `new `clojure.lang.MapEntry (keyword %) %) base-fields)] + `(.seq [] (concat [~@(map #(list `new `clojure.lang.MapEntry (keyword %) %) base-fields)] ~'__extmap)) (let [gk (gensym) gv (gensym)] - `(~'assoc [~gk ~gv] + `(.assoc [~gk ~gv] (condp identical? ~gk ~@(mapcat (fn [fld] [(keyword fld) (list* `new name (replace {fld gv} fields))]) base-fields) (new ~name ~@(remove #{'__extmap} fields) (assoc ~'__extmap ~gk ~gv))))) - `(~'without [k#] (if (contains? #{~@(map keyword base-fields)} k#) + `(.without [k#] (if (contains? #{~@(map keyword base-fields)} k#) (dissoc (with-meta (into {} ~'this) ~'__meta) k#) (new ~name ~@(remove #{'__extmap} fields) (not-empty (dissoc ~'__extmap k#))))))] @@ -142,7 +142,15 @@ 'this' is impliclty bound to the target object (i.e. same meaning as in Java). Note that method bodies are not closures, the local environment includes only the named fields, and those fields can be - accessed directy, i.e. with just foo, not (.foo this). + accessed directy, i.e. with just foo, instead of (.foo this). + + Method definitions take the form: + + (.methodname [args] body) ;note the dot on the methodname! + + The argument and return types can be hinted on the arg and + methodname symbols. If not supplied, they will be inferred, so type + hints should be reserved for disambiguation. The class will have implementations of two (clojure.lang) interfaces generated automatically: IObj (metadata support), ILookup (get and @@ -150,8 +158,8 @@ interface, but don't define methods for it, an implementation will be generated automatically. - In addition, unless you supply a version of hashCode or equals, will - define type-and-value-based equality and hashCode. + In addition, unless you supply a version of .hashCode or .equals, + deftype/class will define type-and-value-based equality and hashCode. Note that overriding equals and hashCode is not supported at this time for deftype - you must use the generated versions." @@ -164,15 +172,15 @@ hinted-fields fields fields (vec (map #(with-meta % nil) fields)) methods (conj methods - `(~'getDynamicType [] ~tag) - `(~'getExtensionMap [] ~'__extmap) - `(~'getDynamicField [k# else#] + `(.getDynamicType [] ~tag) + `(.getExtensionMap [] ~'__extmap) + `(.getDynamicField [k# else#] (condp identical? k# ~@(mapcat (fn [fld] [(keyword fld) fld]) fields) (get ~'__extmap k# else#))) - `(~'hashCode [] (-> ~(hash tag) + `(.hashCode [] (-> ~(hash tag) ~@(map #(list `hash-combine %) fields) (hash-combine ~'__extmap))) - `(~'equals [~'o] + `(.equals [~'o] (boolean (or (identical? ~'this ~'o) (when (instance? clojure.lang.IDynamicType ~'o) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 7d1a0633..0b634bb5 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -5350,9 +5350,12 @@ public static class NewInstanceMethod extends ObjMethod{ static NewInstanceMethod parse(ObjExpr objx, ISeq form, Symbol thistag, Map overrideables) throws Exception{ - //(methodname [args] body...) + //(.methodname [args] body...) NewInstanceMethod method = new NewInstanceMethod(objx, (ObjMethod) METHOD.deref()); - Symbol name = (Symbol)RT.first(form); + Symbol dotname = (Symbol)RT.first(form); + if(!dotname.name.startsWith(".")) + throw new IllegalArgumentException("Method names must begin with '.': " + dotname); + Symbol name = (Symbol) Symbol.intern(null,dotname.name.substring(1)).withMeta(RT.meta(dotname)); IPersistentVector parms = (IPersistentVector) RT.second(form); ISeq body = RT.next(RT.next(form)); try |