Seems like a separate issue to me.

David

On Thu, Dec 25, 2014 at 3:25 PM, Sven Richter <[email protected]> wrote:
> Hi,
>
> while I was preparing the bug report Captaion Obvious hit me again. This also 
> occurs in clojure:
>
> As Thomas said, this is enough to reproduce it:
>
> (def a (atom #{}))
> (reset! a (into (sorted-set) [{:name "foo"}]))
> (swap! a conj {:name "bar"})
>
> -> java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be 
> cast to java.lang.Comparable
>
> Maybe a bug in clojure?
>
> Best Regards,
> Sven
>
> Am Donnerstag, 25. Dezember 2014 19:10:10 UTC+1 schrieb Thomas Heller:
>> I'd imagine it becomes even less obvious once you start using your app and 
>> at some point assoc into an array-map, getting over the threshold and 
>> turning the result into a hash-map. I'd imagine that would be really hard to 
>> track down. Anyways, sorted-set seems to have all sorts of caveats.
>>
>> So probably good to catch it early. :)
>>
>> Pretty interesting stuff in core.async and clojure.core nonetheless.
>>
>> Cheers,
>> /thomas
>>
>>
>> On Thursday, December 25, 2014 6:14:03 PM UTC+1, Sven Richter wrote:
>> > Hi Thomas,
>> >
>> > Thank you for investigating in this.
>> > Your explanation makes perfect sense, given one has the knowledge about 
>> > the internals of clj / cljs and its usage in core.async.
>> >
>> > You are absolutely right about the questionable usage of a set at all for 
>> > this usecase. I used a vector until I tried to make it a sorted set, which 
>> > did not work.
>> >
>> > I am also uncertain if this is a bug or not, however, from plainly using 
>> > the language and the library it is not obvious that a different 
>> > implementation is used inside the go block for {}.
>> >
>> > @dnolen in case you are reading this, should I open a defect for this in 
>> > core.async?
>> >
>> > Best Regards,
>> > Sven
>> >
>> > Am Donnerstag, 25. Dezember 2014 11:34:50 UTC+1 schrieb Thomas Heller:
>> > > Hey,
>> > >
>> > > I figured it out. Fun puzzle. ;)
>> > >
>> > > As expected core.async is not the real villain here, the behavior sure 
>> > > is odd but I'm not sure it is a bug.
>> > >
>> > > The issue is that {:name "test"} inside a go block always gets turned 
>> > > into a hash-map, while outside the better option array-map is chosen by 
>> > > the compiler due to its size. Now sorted-set tries to sort its entries 
>> > > the compare fails cause we have different types.
>> > >
>> > > Clojure:
>> > > (sorted-set (hash-map :test "hello") (array-map :test "world"))
>> > > => ClassCastException clojure.lang.PersistentArrayMap cannot be cast to 
>> > > java.lang.Comparable  clojure.lang.Util.compare (Util.java:153)
>> > >
>> > > ClojureScript:
>> > > (sorted-set (hash-map :test "hello") (array-map :test "world"))
>> > > => Uncaught Error: compare on non-nil objects of different types
>> > >
>> > >
>> > > Feels weird in the beginning but given that sorting is otherwise 
>> > > basically undefined (by which key?) it probably is the only correct 
>> > > behavior. If you supply a comparator for sorted set, everything works as 
>> > > expected.
>> > >
>> > >   (sorted-set-by (comparator (fn [a b] (compare (:test a) (:test b))))
>> > >                  (hash-map :test "hello")
>> > >                  (array-map :test "world"))
>> > >
>> > >
>> > > Probably also better to start out with the sorted-set in your root atom, 
>> > > rather than just replacing the initial vector at some point in time. But 
>> > > given that you want to do UI work, I would suggest staying away from 
>> > > sorted-set altogether and use a vector instead which you sort after 
>> > > doing an insert. I doubt a cursor can point at a specific element in the 
>> > > set cause it is not addressable by index.
>> > >
>> > > HTH,
>> > > /thomas
>> > >
>> > >
>> > >
>> > > On Wednesday, December 24, 2014 10:50:33 PM UTC+1, Sven Richter wrote:
>> > > > Hi Thomas,
>> > > >
>> > > > Thanks for taking the time to answer me.
>> > > >
>> > > > Ok, this is the session namespace, reduced to the relevant parts:
>> > > > (ns de.sveri.structconverter.session
>> > > >   (:require [reagent.cursor :refer [cur]]
>> > > >             [reagent.core :refer [atom]]))
>> > > >
>> > > > (def state (atom {:cur-csv-page nil :files [] :view-state 
>> > > > {:transform-texteditor-style {:display "none"} :delete-modal-file 
>> > > > "iae"} :transformations []}))
>> > > >
>> > > > (def transformations-cur (cur state [:transformations]))
>> > > >
>> > > > And this is referred by @sess/transformations-cur.
>> > > >
>> > > > Adding the log statement produces this output:
>> > > > before swap #{{:name "wer"}}
>> > > >
>> > > > Which is expected, I am using this atom to display some elements in a 
>> > > > select element. It's all working, only time it does not work, is if it 
>> > > > runs inside the go block.
>> > > >
>> > > > I have played around with it a bit more, so there are two aspects.
>> > > >
>> > > > First, how is sess/transformations-cur initialized:
>> > > >
>> > > > If I put the data into a set like this:
>> > > > (when ok (reset! sess/transformations-cur (into (sorted-set) 
>> > > > (:transformations resp))))
>> > > >
>> > > > And then later try to conj something with the said function in the go 
>> > > > block:
>> > > > (swap! sess/transformations-cur conj {:name trans-name})
>> > > >
>> > > > I get the error.
>> > > >
>> > > > On the other hand if I initialize sess/transformations-cur like this:
>> > > > (when ok (reset! sess/transformations-cur (:transformations resp))) 
>> > > > ;(leaving out the set)
>> > > >
>> > > > And then later update it like this in the go block:
>> > > > (swap! sess/transformations-cur conj {:name trans-name}) ; same code 
>> > > > as before it does work.
>> > > >
>> > > > Please note that the updates are triggered manually, so there is 
>> > > > enough time inbetween for every action to finish.
>> > > >
>> > > > And the second aspect is that updates outside of the go block always 
>> > > > work, no matter if it is a set or not.
>> > > >
>> > > > If it's still hard to follow I might put together a small example.
>> > > >
>> > > > Best Regards,
>> > > > Sven
>> > > >
>> > > >
>> > > >
>> > > > Am Mittwoch, 24. Dezember 2014 22:14:02 UTC+1 schrieb Thomas Heller:
>> > > > > That code doesn't help much either since there is still no way to 
>> > > > > tell what sess/transformations-cur is.
>> > > > >
>> > > > > I'd suggest printing the value before trying to swap! it, I see no 
>> > > > > reason anything in there would confuse core.async.
>> > > > >
>> > > > > (defn save-transformation [_]
>> > > > >   (go (let [trans-name (hel/get-value "transformation-name")
>> > > > >             [ok _] (<! (hel/post-async->ch "/cvs/save-transformation"
>> > > > >                                            {:name trans-name
>> > > > >                                             :data 
>> > > > > @sess/transform-history-cur}))]
>> > > > >         (if ok
>> > > > >           (do (.log js/console "before swap" (pr-str 
>> > > > > @sess/transformations-cur))
>> > > > >               (swap! sess/transformations-cur conj {:name 
>> > > > > "foo-name"})
>> > > > >               (h/show-success-message "notification-div" 
>> > > > > "Transformation Saved."))
>> > > > >           (h/show-error-message "notification-div" "Could not save 
>> > > > > Transformation. Something went wrong."))))
>> > > > >
>> > > > >   ;; this immediately executes after the go block starts
>> > > > >   ;; this will most likely happen before (if ok ...)
>> > > > >   ;; if sess/transformations-cur is a set, adding the same obj twice 
>> > > > > will have no effect?
>> > > > >   (swap! sess/transformations-cur conj {:name "foo-name"}))
>> > > > >
>> > > > >
>> > > > > Remember that it is async, so if something does something to 
>> > > > > sess/transformations-cur and leaves it in an unusable state you will 
>> > > > > get errors. It all depends on the speed of the subsequent steps and 
>> > > > > who gets there first.
>> > > > >
>> > > > > Maybe a simple (add-watch sess/transformations-cur (fn [_ _ _ new] 
>> > > > > (prn [:swapped new])) would help tracking down the issue as well (I 
>> > > > > assume its an Atom?). But CLJS core.async is a lot more fragile than 
>> > > > > CLJ so it might actually be a bug, although the operation is quite 
>> > > > > simple so I'd suspect some sort of ordering issue.
>> > > > >
>> > > > > HTH,
>> > > > > /thomas
>> > > > >
>> > > > > On Wednesday, December 24, 2014 3:12:07 PM UTC+1, Sven Richter wrote:
>> > > > > > Hi Thomas,
>> > > > > >
>> > > > > > the code I pasted was maybe a bit misleading.
>> > > > > >
>> > > > > > Function one:
>> > > > > > (defn save-transformation [_]
>> > > > > >   (go (let [trans-name (hel/get-value "transformation-name")
>> > > > > >             [ok _] (<! (hel/post-async->ch 
>> > > > > > "/cvs/save-transformation"
>> > > > > >                                            {:name trans-name
>> > > > > >                                             :data 
>> > > > > > @sess/transform-history-cur}))]
>> > > > > >         (if ok (do(swap! sess/transformations-cur conj {:name 
>> > > > > > "foo-name"})
>> > > > > >                    (h/show-success-message "notification-div" 
>> > > > > > "Transformation Saved."))
>> > > > > >                (h/show-error-message "notification-div" "Could not 
>> > > > > > save Transformation. Something went wrong."))))
>> > > > > >   (swap! sess/transformations-cur conj {:name "foo-name"}))
>> > > > > >
>> > > > > > Function two:
>> > > > > > (defn save-transformation [_]
>> > > > > >   (go (let [trans-name (hel/get-value "transformation-name")
>> > > > > >             [ok _] (<! (hel/post-async->ch 
>> > > > > > "/cvs/save-transformation"
>> > > > > >                                            {:name trans-name
>> > > > > >                                             :data 
>> > > > > > @sess/transform-history-cur}))]
>> > > > > >         (if ok (do nil )
>> > > > > >                (h/show-error-message "notification-div" "Could not 
>> > > > > > save Transformation. Something went wrong."))))
>> > > > > >   (swap! sess/transformations-cur conj {:name "foo-name"}))
>> > > > > >
>> > > > > > Function two works, function one does not. The only difference is 
>> > > > > > when the swap on the cursor happens, either inside the go block 
>> > > > > > (won't work) or outside the go block (does work).
>> > > > > >
>> > > > > > This is the asnyc code I am calling in both cases:
>> > > > > >
>> > > > > > (defn post-async->ch [url method content]
>> > > > > >   (let [ch (chan 1)]
>> > > > > >     (ajax/ajax-request
>> > > > > >       {:uri             url
>> > > > > >        :method          method
>> > > > > >        :params          content
>> > > > > >        :format          (ajax/transit-request-format)
>> > > > > >        :response-format (ajax/transit-response-format)
>> > > > > >        :handler         (fn [resp](put! ch resp))})
>> > > > > >     ch))
>> > > > > >
>> > > > > > The error message indeed seems weird, but everything I tried so 
>> > > > > > far indicates a bug or a missing feature in core.async.
>> > > > > >
>> > > > > > In the meantime I even refactored my code to remove every 
>> > > > > > core.async bit from the ajax calls and it works as expected then 
>> > > > > > (by working with callbacks instead).
>> > > > > >
>> > > > > > Best Regards,
>> > > > > > Sven
>> > > > > >
>> > > > > > Am Mittwoch, 24. Dezember 2014 14:23:35 UTC+1 schrieb Thomas 
>> > > > > > Heller:
>> > > > > > > Cannot say without the rest of the code but I what is in 
>> > > > > > > (:transformations resp)? sorted-set doesn't work if one item 
>> > > > > > > doesn't compare to another (eg. numbers vs maps).
>> > > > > > >
>> > > > > > > Suppose:
>> > > > > > >
>> > > > > > > (def a (atom #{}))
>> > > > > > > => (var user/a)
>> > > > > > > (reset! a (into (sorted-set) [1 2 2 2 3]))
>> > > > > > > => #{1 2 3}
>> > > > > > > (conj @a {:name "test"})
>> > > > > > > ClassCastException clojure.lang.PersistentArrayMap cannot be 
>> > > > > > > cast to java.lang.Comparable  clojure.lang.Util.compare 
>> > > > > > > (Util.java:153)
>> > > > > > >
>> > > > > > > Doesn't look like a core.async issue?
>> > > > > > >
>> > > > > > >
>> > > > > > > HTH,
>> > > > > > > /thomas
>> > > > > > >
>> > > > > > >
>> > > > > > > On Wednesday, December 24, 2014 11:19:04 AM UTC+1, Sven Richter 
>> > > > > > > wrote:
>> > > > > > > > Hi,
>> > > > > > > >
>> > > > > > > > Using the latest core.async (v0.1.346.0-17112a-alpha) updating 
>> > > > > > > > a sorted set results in an error.
>> > > > > > > >
>> > > > > > > > I have this code:
>> > > > > > > >
>> > > > > > > > (defn get-transformations []
>> > > > > > > >   (go (let [[ok resp] (<! (h/get-async 
>> > > > > > > > "/csv/all-transformations"))]
>> > > > > > > >         ;(when ok (reset! sess/transformations-cur 
>> > > > > > > > (:transformations resp)) ;works
>> > > > > > > >         (when ok (reset! sess/transformations-cur (into 
>> > > > > > > > (sorted-set) (:transformations resp))) ;does not work
>> > > > > > > >                  (println (conj @sess/transformations-cur 
>> > > > > > > > {:name "test"}))))))
>> > > > > > > >
>> > > > > > > > where transformations-cur is a reagent cursor on a reagent 
>> > > > > > > > atom.
>> > > > > > > >
>> > > > > > > > The second reset throws this error (Actually the error occurs 
>> > > > > > > > on updating the cursor (conj @sess/transformations-cur {:name 
>> > > > > > > > "test"})):
>> > > > > > > > Uncaught Error: compare on non-nil objects of different types 
>> > > > > > > > in ioc_helpers:41
>> > > > > > > >
>> > > > > > > > Are sorted sets not supported?
>> > > > > > > >
>> > > > > > > > How do others keep there sets / lists sorted in the UI?
>> > > > > > > >
>> > > > > > > > Of course I could sort it every time I display it, but it 
>> > > > > > > > seems to be more correct to keep it sorted inside the state.
>> > > > > > > >
>> > > > > > > > Best Regards,
>> > > > > > > > Sven
>
> --
> Note that posts from new members are moderated - please be patient with your 
> first post.
> ---
> You received this message because you are subscribed to the Google Groups 
> "ClojureScript" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/clojurescript.

-- 
Note that posts from new members are moderated - please be patient with your 
first post.
--- 
You received this message because you are subscribed to the Google Groups 
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/clojurescript.

Reply via email to