Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug with MapEntry ? #265

Open
DjebbZ opened this issue Oct 20, 2018 · 1 comment
Open

Bug with MapEntry ? #265

DjebbZ opened this issue Oct 20, 2018 · 1 comment

Comments

@DjebbZ
Copy link
Contributor

DjebbZ commented Oct 20, 2018

Hello, long time no issue :)

I think I found a bug yesterday while using specter. When navigating into map entries, I noticed that you can call Clojure's key on it while in a select, but not when in a transform/multi-transform/set-val. My understanding (and the error I got) is that a MapEntry is kept as is in a select, but is transformed into a PersistentVector while in a transform.

Below a complete reproduction of the bug, and also a show case of what I was trying to do (navigating to map entries where the key isn't some specific key):

> clj -Sdeps "{:deps {org.clojure/clojure {:mvn/version \"1.9.0\"} com.rpl/specter {:mvn/version \"1.1.1\"}}}"
Clojure 1.9.0
user=> (require '[com.rpl.specter :as sp])
nil
user=> (def data {:a 1 :b 2 :c 3})
#'user/data
user=> (sp/select [sp/ALL #(not= (key %) :a)] data) ;; works as expected
[[:b 2] [:c 3]]
user=> (sp/setval [sp/ALL #(not= (key %) :a)] sp/NONE data) ;; `key` fails
ClassCastException clojure.lang.PersistentVector cannot be cast to java.util.Map$Entry  clojure.core/key (core.clj:1559)
user=> (sp/setval [sp/ALL #(not= (first %) :a)] sp/NONE data) ;; `first` OK
{:a 1}
user=> (sp/transform [sp/ALL #(not= (key %) :a)] sp/NONE data) `key` fails
ClassCastException clojure.lang.PersistentVector cannot be cast to java.util.Map$Entry  clojure.core/key (core.clj:1559)
user=> (sp/transform [sp/ALL #(not= (first %) :a)] sp/NONE data) `first` OK
{:a 1}
user=> (sp/multi-transform [sp/ALL #(not= (key %) :a) (sp/terminal sp/NONE)] data) `key` fails
ClassCastException clojure.lang.PersistentVector cannot be cast to java.util.Map$Entry  clojure.core/key (core.clj:1559)
user=> (sp/multi-transform [sp/ALL #(not= (first %) :a) (sp/terminal sp/NONE)] data) `first` fails
{:a 1}
user=> (sp/multi-transform [sp/ALL #(not= (first %) :a) (sp/terminal-val sp/NONE)] data) trying `terminal-val` instead of `terminal` out of curiosity
{:a 1}
user=> (sp/multi-transform [sp/ALL #(not= (key %) :a) (sp/terminal-val sp/NONE)] data) `key` fails
ClassCastException   [trace missing]
user=> 

Bug? To be clear, for me the bug is that MapEntry are transformed to Vector whereas I expected them to be MapEntry.

End of report!

@jeff303
Copy link
Contributor

jeff303 commented Aug 3, 2020

This is happening because small maps (PersistentArrayMap) store the keys and values in a single array, and the all-transform is operating on entries as two-item vectors (here).

I suspect there may be some way to reassign key to first when evaluating this anonymous function (only when the structure is a PersistentArrayMap, i.e. using the protocol mechanism).

For now, though, it seems that using MAP-KEYS with a predicate does what you want.

(sp/setval [sp/MAP-KEYS (sp/pred #(not(= :a %)))] sp/NONE data)
{:a 1}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants