clj-commons / potemkin

some ideas which are almost good
572 stars 53 forks source link

AbstractMethodError when using def-map-type without defining meta #26

Closed cespare closed 10 years ago

cespare commented 10 years ago

Potemkin: 0.3.7 Clojure: 1.6.0 Java: 1.7

Having trouble with even the simple example from the README. This is in a fresh repl:

user=> (require '[potemkin.collections :refer [def-map-type]])
nil
user=> 

user=> (def-map-type LazyMap [m]   
  #_=>   (get [_ k default-value]
  #_=>     (if (contains? m k)
  #_=>       (let [v (get m k)]
  #_=>         (if (instance? clojure.lang.Delay v)
  #_=>           @v
  #_=>           v))
  #_=>       default-value))
  #_=>   (assoc [_ k v]
  #_=>     (LazyMap. (assoc m k v)))
  #_=>   (dissoc [_ k]
  #_=>      (LazyMap. (dissoc m k)))
  #_=>   (keys [_]
  #_=>     (keys m)))
user.LazyMap
user=> (LazyMap. {})

AbstractMethodError user.LazyMap.meta_STAR_()Ljava/lang/Object;  user.LazyMap (form-init3281556375762400900.clj:78)
user=> (->LazyMap {})

AbstractMethodError user.LazyMap.meta_STAR_()Ljava/lang/Object;  user.LazyMap (form-init3281556375762400900.clj:78)

Defining a meta method fixes it, but the README implies that it shouldn't be required:

Despite this, there are only four functions which really matter: get, assoc, dissoc, and keys. def-map-type is a variant of deftype which, if those four functions are implemented, will look and act like a Clojure map.

(def-map-type LazyMap [m]   
  (get [_ k default-value]
    (if (contains? m k)
      (let [v (get m k)]
        (if (instance? clojure.lang.Delay v)
          @v
          v))
      default-value))
  (assoc [_ k v]
    (LazyMap. (assoc m k v)))
  (dissoc [_ k]
     (LazyMap. (dissoc m k)))
  (keys [_]
    (keys m)
  (meta [_] nil)) ; this makes the readme example work
ztellman commented 10 years ago

This is because the REPL is calling meta, but you're right that this shouldn't be happening.

cespare commented 10 years ago

Thanks!