weird clojurescript encoding of UUID from transit

270 views
Skip to first unread message

Colin Yates

unread,
Sep 25, 2015, 5:19:23 PM9/25/15
to ClojureScript
First, this is almost certainly my fault but I am scratching my head how to proceed.

I am using transit (json) to send messages from the server to the client and it is working great except my UUIDs don’t seem to be coming across:

cljs.user=> id
#uuid "9e7200f4-419c-461e-a9e5-f6b07f8dcd8f"
cljs.user=> (type id)
#object[Function "function (high, low) {
this.high = high;
this.low = low;
this.hashCode = -1;
}"]

previously (type id) would return cljs.core/UUID. Transit is working elsewhere - it is converting sequences and keywords etc., but every UUID has the above type.

If I go to a fig wheel REPL and create a new UUID then it correctly reports the type as "cljs.core/UUID".

I have no idea how to proceed or how to interpret the result of (type id).

Any pointers?

Thanks.

Ivan Willig

unread,
Sep 25, 2015, 5:41:29 PM9/25/15
to clojur...@googlegroups.com
I believe this is because the `type` function returns a type's
constructor function in JavaScript parlance. You can find `type` here.

https://github.com/clojure/clojurescript/blob/2fa41e7969d22f72876122d2250baf4ef936e6e9/src/main/cljs/cljs/core.cljs#L250-L254

Under the hood, transit-cljs uses transit-js as you can see here,
https://github.com/cognitect/transit-cljs/blob/master/src/cognitect/transit.cljs#L110

And the constructor function for a UUID in transit-js looks like
https://github.com/cognitect/transit-js/blob/620906704f9f6904745895878ad3228607836d31/src/com/cognitect/transit/types.js#L248-L252.

I would guess that you are getting back the
com.cognitect.transit.types.UUID type and not the clojurescript
version of a UUID. When you create a UUID in the repl you are of
course getting the cljs version UUID.

However, I just started to understand transit so I maybe wrong.

Hope this helps.
Ivan Willig
> --
> 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 clojurescrip...@googlegroups.com.
> To post to this group, send email to clojur...@googlegroups.com.
> Visit this group at http://groups.google.com/group/clojurescript.

Colin Yates

unread,
Sep 25, 2015, 6:03:07 PM9/25/15
to clojur...@googlegroups.com
Definitely something weird going on. If I don’t use transit and just use pr-str/read-string then it works fine.

Ivan Willig

unread,
Sep 25, 2015, 6:41:51 PM9/25/15
to clojur...@googlegroups.com
That would be what I would except from my reading of the transit-cljs
code. Is there a reason you need your UUID's to be cljs.core.UUIDs
instead of a com.cognitect.transit.types.UUID ?

If you need to check if a value was a UUID you could always write
something like,

(defn uuid? [u] (instance? com.cognitect.transit.types.UUID u))
Ivan Willig

Colin Yates

unread,
Sep 25, 2015, 6:50:16 PM9/25/15
to clojur...@googlegroups.com
I have a bunch of prismatic schemas that all reference cljs.core.UUID but I can change them. I am always a little surprised and concerned when previously working code suddenly stops, and I had no idea how to progress after (type id) printed out something like an object ;-).

@jaen on Slack pointed out https://github.com/tonsky/datascript/issues/110 which seems relevant.

Nikita Prokopov

unread,
Sep 26, 2015, 6:06:38 PM9/26/15
to ClojureScript
Having two UUID types around is not a good idea. Transit shouldn’t have its own type, but since it’s there, I recommend re-configure transit reader to always read native CLJS UUIDs:

(defn read-transit-str [s]
(t/read (t/reader :json { :handlers {"u" cljs.core/uuid} }) s))

You‘ll save yourself A LOT of headache, trust me

Jamie Orchard-Hays

unread,
Sep 26, 2015, 7:13:40 PM9/26/15
to clojur...@googlegroups.com
Why *does* Transit have another UUID type? I was surprised to see that.

Colin Yates

unread,
Sep 26, 2015, 7:14:47 PM9/26/15
to clojur...@googlegroups.com
Yeah, I wondered that too. Given that cljs.core/uuid was already established…

I am sure (and hope!) there is a good technical reason.

Daniel Compton

unread,
Sep 27, 2015, 2:27:13 AM9/27/15
to clojur...@googlegroups.com
I think this is the best discussion I've seen on the two UUID types in Transit https://github.com/cognitect/transit-cljs/pull/10
Daniel

Colin Yates

unread,
Sep 27, 2015, 4:37:43 AM9/27/15
to ClojureScript
Thanks Daniel.

That thread troubles me greatly - please see https://github.com/cognitect/transit-cljs/pull/10#issuecomment-143528738 for more thoughts.

David Nolen

unread,
Sep 27, 2015, 11:29:32 AM9/27/15
to clojur...@googlegroups.com
The transit-cljs type table (https://github.com/cognitect/transit-cljs#default-type-mapping) specifically states you will get com.cognitect.transit/UUID.

David

David Nolen

unread,
Sep 27, 2015, 11:38:02 AM9/27/15
to clojur...@googlegroups.com
Transit's UUID stores the byte representation and provides methods for accessing the lower and higher bits, cljs.core's UUID is just a simple wrapper around a string.

Transit provides a uuid? predicate for this reason. Though perhaps it would be better to provide a marker protocol in cljs.core instead for this case a la IRecord and test this in cljs.core/uuid?

David

Nikita Prokopov

unread,
Sep 27, 2015, 2:09:06 PM9/27/15
to clojur...@googlegroups.com
Why don’t just do simple and no surprise thing first (return cljs.core/UUID), and make optimizations optional?

Transit’s UUIDs are not even performance optimization: every time you want to compare/hash/equiv them, this code is called https://github.com/cognitect/transit-js/blob/master/src/com/cognitect/transit/types.js#L286-L298. toString is very much not free on transit’s UUIDs, but it _is_ free on cljs UUIDs. Additional time is also spent on read for _every_ instance of UUID to convert it to hi/low bit format — and for most people out there for most of the times, they will never get any benefits from that.

A lot of effort has been spent already, and you can spend some more, making it look like these two are in fact the same type (in the end, they will never be anyways), but I don’t see any justification for that. What’s that important reason that explains why we’re making things more complicated that they should be?



You received this message because you are subscribed to a topic in the Google Groups "ClojureScript" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojurescript/_B52tadgUgw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojurescrip...@googlegroups.com.

Nikita Prokopov

unread,
Sep 27, 2015, 2:12:26 PM9/27/15
to clojur...@googlegroups.com
Sorry, I haven’t finished previous letter.

If Cognitect depends so much on hi/low bits functions, you can _opt in_ to using your own UUID type. Clean, simple and predictable by default, opt-in optimizations when you need them. Are there any issues with that approach?

This issue ate a lot of my own time, since then, at least two other people was hurt as well. It would be great to see it fixed.

With respect,
Nikita.

David Nolen

unread,
Sep 27, 2015, 3:26:58 PM9/27/15
to clojur...@googlegroups.com
The default has been established for some time and has been documented. It's now water under the bridge.

David

Daniel Compton

unread,
Sep 27, 2015, 4:17:29 PM9/27/15
to clojur...@googlegroups.com
“All support tickets are either product bugs or documentation bugs.” - Gwen Shapira

Another option if the UUID type is staying the same would be to add a note on this to the Transit-cljs README. It would explicitly point out that a cct UUID is used instead, and give instructions for how to override that type to create a cc UUID with:

(defn read-transit-str [s]
  (t/read (t/reader :json { :handlers {"u" cljs.core/uuid} }) s))


While it is true that the transit-cljs README does document this, it's in the middle of a large list of types and is easily overlooked (as evidenced by the several people who have spent a lot of time trying to understand what's going on).
Daniel
Reply all
Reply to author
Forward
0 new messages