Language request: make key and val work on vector pairs too

5 views
Skip to first unread message

samppi

unread,
Nov 11, 2009, 12:52:49 PM11/11/09
to Clojure
Clojure 1.1.0-alpha-SNAPSHOT
user=> (conj (first {1 2}) 3)
[1 2 3]
user=> (conj {1 2} [2 5])
{2 5, 1 2}
user=> (key (first {1 2}))
1
user=> (key [1 2])
java.lang.ClassCastException: clojure.lang.PersistentVector cannot be
cast to java.util.Map$Entry (NO_SOURCE_FILE:0)

In all respects but one, two-sized vectors act like map entries, and
map entries act like two-sized vectors. This single exception is the
exception that the key and val forms throw when called on two-sized
vectors.

Almost one year ago, when I was completely new at Clojure, I asked
about creating map entries (http://groups.google.com/group/clojure/
browse_thread/thread/15572b6c7269096e/ab113323410dc39e). Rich Hickey
made it clear, though, that while he wants key and val to be used on
map entries, he does not want map entries to be created directly by
the user, and that map entries could be removed at any time.

I presumed in the past year that he wanted us to use vectors whenever
we wanted to create map entries, since he designed Clojure so that map
entries are equivalent to vector pairs and vice versa. But in one
aspect, this does not work. Let me give an example—processing pairs:

user=> (defn a [pairs]
(map #(vector (key %) (inc (val %))) pairs))
#'user/a
user=> (defn b [pairs]
(map #(vector (key %) (* (val %) 2)) pairs))
#'user/b
user=> (a {:a 3, :b 2})
([:a 4] [:b 3])
user=> (b {:a 3, :b 2})
([:a 6] [:b 4])
user=> ((comp a b) {:a 3, :b 2})
java.lang.ClassCastException: clojure.lang.PersistentVector cannot be
cast to java.util.Map$Entry

If we are not to create map entries directly, but use vector pairs
instead, then I would like vector pairs to act more like map entries:
the key and val functions should work on vectors too. This would be
elegant and complete the equivalence between map entries and vector
pairs. If this should not be, then what would be the rationale?
Otherwise, the user should be able to just create map entries instead,
since Clojure 1.0 definitely has map entries now.

ataggart

unread,
Nov 11, 2009, 1:54:04 PM11/11/09
to Clojure
Just use first and second for both cases.

samppi

unread,
Nov 13, 2009, 1:50:33 PM11/13/09
to Clojure
That works, but I don't think it's satisfactory. first and second
aren't the intended functions to access a map entry's keys and vals—
but most importantly, it's been documented that second is very, very
slow compared to val (http://w01fe.com/blog/2009/01/more-on-clojure-
map-accessor-speeds/). second, in fact, is so slow, I would never use
it if there's a chance that it would be called on map entries, even if
it would be cleaner and more abstract; I'd have to write my code
around the fact that val doesn't work on vector pairs. I think that
key and val on vector pairs is a great way to make dealing with maps
and their entries more elegant, especially since vector pairs work as
map entries in every other case. Is there a good reason why Clojure
1.1 shouldn't allow val on vector pairs?
Reply all
Reply to author
Forward
0 new messages