clojure.walk/postwalk does not preserve MapEntry type objects

Description

This came up on Slack. A naïve implementation of "lispify" to turn vectors into lists used this code:

But when called like this:

It produces this error: java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.util.Map$Entry

My initial reaction was to change the condition to (and (vector? e) (not (map-entry? e))) but that still failed, because while walking the hash map, the MapEntry [:a "b"] was turned into a PersistentVector.

At this point, we can switch to using prewalk and it works as expected:

Now we get the expected result:

This seems unintuitive at best and feels like a bug: postwalk should preserve the MapEntry type rather than converting it to a PersistentVector.

Cause: The problem seems to be this line https://github.com/clojure/clojure/blob/master/src/clj/clojure/walk.clj#L45:

Proposed: Change to:

This would preserve the type of the subelement.

Patch: clj-2031-w-test-v2.diff
Screened by: Alex Miller

Environment

None

Attachments

2

Activity

Show:

Alex Miller July 27, 2017 at 9:39 PM

It's in a list for Rich to look at.

Sean Corfield July 27, 2017 at 9:21 PM

This keeps coming up on Slack – given there's a patch and this is prescreened, can it just get fixed as part of the next Clojure 1.9.0 Alpha/Beta build?

Jozef Wagner October 27, 2016 at 2:42 PM

Good catch, thanks! Added patch clj-2031-w-test-v2.diff that uses key and val instead.

Alex Miller October 27, 2016 at 2:34 PM

Instead of the calls to .key and .val you should just call key and val.

Jozef Wagner October 27, 2016 at 2:19 PM

Added patch with test

Completed

Details

Assignee

Reporter

Labels

Approval

Ok

Patch

Code and Test

Priority

Affects versions

Fix versions

Created October 2, 2016 at 1:32 AM
Updated September 14, 2018 at 10:21 PM
Resolved September 14, 2018 at 10:21 PM