clerk icon indicating copy to clipboard operation
clerk copied to clipboard

ClassCastException when presenting `tech.v3.dataset`

Open mk opened this issue 1 year ago • 6 comments

full repro at https://github.com/pieterbreed/clerk-dataset-repro by @pieterbreed

Also reported on Clojurians slack https://clojurians.slack.com/archives/C035GRLJEP8/p1724429010102259

mk avatar Aug 29 '24 10:08 mk

This seems to be a smaller repro of what's going wrong:

(def ds
  (let [ds (tech.v3.dataset/mapseq-parser)]
    (doseq [x (for [i (range 100)]
                {:x i
                 :y (java.time.Instant/now)})]
      (ds x))
    (ds)))

(into [] (take 3) (:x ds)) ;; works
(into [] (take 3) (:y ds)) ;; throws ClassCastException

I don't know enough about tech.v3.dataset to know why the type of column changes where I can do take and where I cannot.

mk avatar Aug 29 '24 10:08 mk

Given the exception (during presentation)

Execution error (ClassCastException) at nextjournal.clerk.viewer/present+paginate-children (viewer.cljc:1627).
class clojure.lang.Reduced cannot be cast to class clojure.lang.ITransientCollection (clojure.lang.Reduced and clojure.lang.ITransientCollection are in unnamed module of loader 'app')

	at nextjournal.clerk.viewer$present_PLUS_paginate_children.invokeStatic(viewer.cljc:1627)
	at nextjournal.clerk.viewer$present_PLUS_paginate_children.invoke(viewer.cljc:1618)
	at nextjournal.clerk.viewer$present_STAR_.invokeStatic(viewer.cljc:1691)

I guess it has to do with the into there. This change fixes showing the notebook, but maybe it's worth to dig a bit deeper.

diff --git a/src/nextjournal/clerk/viewer.cljc b/src/nextjournal/clerk/viewer.cljc
index bf431dcb..2a20c1e5 100644
--- a/src/nextjournal/clerk/viewer.cljc
+++ b/src/nextjournal/clerk/viewer.cljc
@@ -1623,11 +1623,11 @@
                       (update :n min @!budget))
         children (if preserve-keys?
                    (into {} (map (fn [[k v]] [k (present* (inherit-opts wrapped-value v k))])) xs)
-                   (into []
-                         (comp (if paginate? (drop+take-xf fetch-opts') identity)
-                               (map-indexed (fn [i x] (present* (inherit-opts wrapped-value x (+ i (or offset 0))))))
-                               (remove nil?))
-                         (ensure-sorted xs)))
+                   (vec
+                    (sequence (comp (if paginate? (drop+take-xf fetch-opts') identity)
+                                    (map-indexed (fn [i x] (present* (inherit-opts wrapped-value x (+ i (or offset 0))))))
+                                    (remove nil?))
+                              (ensure-sorted xs))))
 

and pagination also works here

Screenshot 2024-08-29 at 17 31 29

zampino avatar Aug 29 '24 15:08 zampino

Maybe the reduce from into receives conflicting calls to reduced.

zampino avatar Aug 29 '24 15:08 zampino

Here is a more minimal repro, and a workaround:

user> (require '[tech.v3.dataset :as ds])
nil
user> (import 'java.time.Instant)
java.time.Instant
user> (def ds (ds/->dataset {:x (range 5) :y (repeatedly 5 #(java.time.Instant/now))}))
#'user/ds
user> ds
_unnamed [5 2]:

| :x |                          :y |
|---:|-----------------------------|
|  0 | 2024-08-29T15:54:57.987431Z |
|  1 | 2024-08-29T15:54:57.988432Z |
|  2 | 2024-08-29T15:54:57.988455Z |
|  3 | 2024-08-29T15:54:57.988458Z |
|  4 | 2024-08-29T15:54:57.988461Z |
user> (take 3 (:x ds))
(0 1 2)
user> (take 3 (:y ds))
(#object[java.time.Instant 0xf3f2e65 "2024-08-29T15:54:57.987431Z"]
 #object[java.time.Instant 0x10dd3c7 "2024-08-29T15:54:57.988432Z"]
 #object[java.time.Instant 0x1ff353ba "2024-08-29T15:54:57.988455Z"])
user> (into [] (take 3) (:x ds))
[0 1 2]
user> (into [] (take 3) (:y ds))
Execution error (ClassCastException) at user/eval59642 (form-init362550846257869959.clj:43).
class clojure.lang.Reduced cannot be cast to class clojure.lang.ITransientCollection (clojure.lang.Reduced and clojure.lang.ITransientCollection are in unnamed module of loader 'app')
user> (into [] (take 3) (vec (:y ds)))
[#object[java.time.Instant 0x6e058d1e "2024-08-29T15:54:57.987431Z"]
 #object[java.time.Instant 0x6bb8eb57 "2024-08-29T15:54:57.988432Z"]
 #object[java.time.Instant 0x59e0600a "2024-08-29T15:54:57.988455Z"]]

You can log this in https://github.com/techascent/tech.ml.dataset if you'd like.

harold avatar Aug 29 '24 15:08 harold

Thanks @harold, I've opened the attached issue using your smaller repro.

mk avatar Sep 02 '24 06:09 mk

:+1: - nice, thanks! Could be a good bug.

harold avatar Sep 03 '24 16:09 harold