LinkedHashMap not well supported

818 views
Skip to first unread message

Kurt Harriger

unread,
Apr 29, 2012, 9:48:07 PM4/29/12
to clo...@googlegroups.com
I am using a groovy library that returns a LinkedHashMap containing ArrayLists and nested LinkedHashMaps.  I did not expect any issues working with this in clojure since this type implements java.util.Map I figured everything would just work. However the first thing I tried to do was apply clojure.set/keywordize-keys which didn't keywordize the keys as expected.  I then tried map? which returned false, I figured I would then try to convert to clojure map using apply hash-map which threw an illegalargumentexception. into {} however did work. I then attempted to use clojure.walk/postwalk to convert LinkedHashMaps to clojure maps which only visited the top node.  However using prewalk did work, so I ended up with the following helper function.  

(defn- convert-types
  [groovy-result]
  (walk/prewalk
   (fn [x]
     (cond (instance? java.util.LinkedHashMap x) (into {} x)
           (instance? java.util.ArrayList x)  (vec x)  ;; probably not required but I wanted to pr-str to print as vectors rather than #ArrayList ...
           :else x)) groovy-result))

clojure map? is defined as:
 (fn ^:static map? [x] (instance? clojure.lang.IPersistentMap x)))

Is there any reason map? checks explicitly for clojure.lang.IPersistentMap rather than java.util.Map? 

also clojure.walk/walk contains: 
..
  (instance? clojure.lang.IMapEntry form)
..

but (first m) returns java.util.LinkedHashMap$Entry which extends java.util.Map$Entry and java.util.HashMap$Entry.

I'm not sure why into {} works but apply hash-map doesn't, seems to have to do with first and next don't work on java.util.LinkedHashMap$Entry either.

Seems like many of these functions could be improved to work with java.util.Map and  java.util.Map$Entry?  
Should a JIRA be created for these?

Softaddicts

unread,
Apr 29, 2012, 11:18:43 PM4/29/12
to clo...@googlegroups.com
Obviously, LinkedHashMap is not a Clojure persistent data structure.
map? and alikes tests interfaces specific to Clojure, not Java ones.

Clojure data structures implement java.util.Map and cie to ease interop
with Java but they are not the same as the persistent interfaces and do not
allow mutations contrary to Java data structures.

There is enough behavior differences (not withstanding the different hosts
running Clojure) to mandate a clean separation between both worlds.

Have a look at this:

http://grokbase.com/t/gg/clojure/11afb4wmb3/recursively-convert-java-map-to-clojure-map

It should get you started :)

Luc
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
--
Softaddicts<lprefo...@softaddicts.ca> sent by ibisMail!

kurtharriger

unread,
Apr 29, 2012, 11:51:25 PM4/29/12
to clo...@googlegroups.com
Ill agree that it may be approriate for map? to return false as it does perhaps imply a stricter contract then the jvm versions namely immutability. However, I fully expected the return type of keywordize to be a new immutable clojure map and it would be extreamly helpful if walk, hash-map, first, next, rest supported map$entry. IMHO one of the best things about clojure is that it is very easy to interop with jvm libraries without a lot of type conversion and/or wrapper types.

Stuart Halloway

unread,
Apr 30, 2012, 11:46:22 AM4/30/12
to clo...@googlegroups.com
Ill agree that it may be approriate for map? to return false as it does perhaps imply a stricter contract then the jvm versions namely immutability.  However, I fully expected the return type of keywordize to be a new immutable clojure map and it would be extreamly helpful if walk, hash-map, first, next, rest supported map$entry. IMHO one of the best things about clojure is that it is very easy to interop with jvm libraries without a lot of type conversion and/or wrapper types.

Patch improving walk *definitely* welcome. This has bitten me before too.

If you take this on, you may want to look at (or use) EqualityPartition in clojure.data, which attempts to categorize collections.

Stuart Halloway
Clojure/core
http://clojure.com

kurtharriger

unread,
Apr 30, 2012, 10:53:35 PM4/30/12
to clo...@googlegroups.com
Sounds good. Ill submit a patch for walk. Im not real sure why apply hash-map didnt work, but if figure it out Ill add that too.

Alan Malloy

unread,
May 1, 2012, 1:22:35 AM5/1/12
to Clojure
On Apr 30, 7:53 pm, kurtharriger <kurtharri...@gmail.com> wrote:
> Sounds good. Ill submit a patch for walk. Im not real sure why apply hash-map didnt work, but if figure it out Ill add that too.

For the same reason that (apply hash-map {1 2, 3 4}) doesn't work: the
maps seqs as ([1 2] [3 4]), not as (1 2 3 4).

Michał Marczyk

unread,
May 1, 2012, 11:12:32 AM5/1/12
to clo...@googlegroups.com
And because of that, into would work:

user> (into {} (doto (java.util.LinkedHashMap.) (.put :foo 1) (.put :bar 2)))
{:foo 1, :bar 2}

M.
Reply all
Reply to author
Forward
0 new messages