summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2009-10-30 13:23:13 -0400
committerRich Hickey <richhickey@gmail.com>2009-10-30 13:23:13 -0400
commit9c3e97a85c042d2c3f276f0c1e0d270db35553aa (patch)
tree201bb9c0beea2deed36452f9b9bd870f7bb460e7 /src
parent1c8e76b1a0e6616c780902a317a7ab9a8423288b (diff)
methodnames now take form (.methodname [args] body) in reify/deftype/class
Diffstat (limited to 'src')
-rw-r--r--src/clj/clojure/core.clj16
-rw-r--r--src/clj/clojure/core_deftype.clj58
-rw-r--r--src/jvm/clojure/lang/Compiler.java7
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