Sometimes You Feel Like a Map

Creating your own data type that behaves like a map is pretty straight forward. The tricky part is figuring out which interfaces you need to implement to enable the different parts of Clojure's map API. The following is an overview of what is necessary to make your custom type behave like a map on the JVM.

clojure.lang.Associative

The Associative interface gives you the APIs necessary to put stuff into your map and check to see that it's there.

  Associative
  (containsKey [this key])
  (entryAt [this key])
  (assoc [this key value])

Watch Out

API Calls

clojure.lang.ILookup

Where Associative lets you add to your map, ILookup provides the API for getting things out again.

  ILookup
  (valAt [this k])
  (valAt [this k not-found])

API Calls

clojure.lang.IFn

The IFn interface is what allows your map to be called as a function (See API Calls below).

  IFn
  (invoke [this k])
  (invoke [this k not-found])

API Calls

clojure.lang.IPersistentCollection

  IPersistentCollection
  (cons [this o])
  (count [this])
  (empty [this])
  (equiv [this o])

Watch Out

API Calls

clojure.lang.IPersistentMap

Having already implemented Associative, we get a free pass on this assoc. assocEx is pretty much the same except that it throws an exception if the key already exists. without has the same behavior as dissoc.

  IPersistentMap
  (assoc [this k v])
  (assocEx [this k v])
  (without [this k])

API Calls

clojure.lang.Seqable

The Seqable interface is by far the biggest bang for the buck. Implement one function and you get a sizable chunk of the map and collection APIs.

  Seqable
  (seq [this])

Watch Out

API Calls

java.lang.Iterable

Seeing as you've already implemented seq, this one is a no brainer. You can simply wrap the result of calling seq on your map into a clojure.lang.SeqIterator and call it a day.

  Iterable
  (iterator [this])

API Calls

Wrap Up

You should now have a custom type that you can treat just like any other map. You can find examples of other custom maps in crosshair, mapstache, and strata.

If you notice mistakes, typo or otherwise, feel free to let me know @thenandagain on Twitter, or send a pull request.