Skip to content

Issues with ordered/map data literals #77

Open
@yuhan0

Description

@yuhan0

The #ordered/map data literal constructs an invalid data structure when read in the REPL, but not when used in a def form.

Minimal repro at the REPL:

$ clj -Sdeps '{:deps {org.flatland/ordered {:mvn/version "1.15.12"}}}'
Clojure 1.12.0
user=> (require '[flatland.ordered.map :as o])
nil

user=> (get (o/ordered-map [[:a 1]]) :a)
1

user=> (get #ordered/map [[:a 1]] :a)
Execution error (ClassCastException) at flatland.ordered.map.OrderedMap/valAt (map.clj:51).
class clojure.lang.PersistentVector cannot be cast to class clojure.lang.MapEntry (clojure.lang.PersistentVector and clojure.lang.MapEntry are in unnamed module of loader 'app')

Extended repro as source file:

(ns repro (:require [flatland.ordered.map :as o])

(def m1 #ordered/map [[:a 1]])

(let [m #ordered/map [[:a 1]]]
  (def m2 m))

(#(def m3 #ordered/map [[:a 1]]))

(keys m1) ;; => (:a)
(keys m2) ;; boom
(keys m3) ;; boom

(map class m1) ;; => (clojure.lang.MapEntry)
(map class m2) ;; => (clojure.lang.PersistentVector)
(map class m3) ;; => (clojure.lang.PersistentVector)

Something about Clojure's reader or this library's internals appears to be preventing the vectors from being cast into map entries or vice versa, causing the constructed object to be invalid and blow up when one tries to manipulate it.

The relevant data reader is

(defn ordered-map-reader-clj [coll]

Note: it's possible to delay construction of the object to runtime as in the ordered-map-reader-cljs, but as hiredman pointed out in the linked Slack discussion, this would break the ability for macros to work with these ordered-map literals.

I attempted to fix it by having the reader explicitly cast to MapEntry, but this also fails:

(defn my-ordered-map-reader
  "does not work!"
  [coll]
  (into (ordered-map)
        (map (fn [[k v]] (clojure.lang.MapEntry/create k v)))
        coll))

(set! *data-readers*
      (assoc *data-readers* 'o/map #'my-ordered-map-reader))

(map class #o/map ([:a 1])) ;; => (clojure.lang.PersistentVector)
(keys #o/map ([:a 1])) ;; boom

More discussion and context at:
https://clojurians.slack.com/archives/C03S1KBA2/p1742444212617369

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions