This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-20
Channels
- # admin-announcements (1)
- # announcements (1)
- # beginners (115)
- # calva (31)
- # cider (25)
- # clj-kondo (47)
- # cljdoc (23)
- # cljs-dev (5)
- # clojars (1)
- # clojure (60)
- # clojure-australia (1)
- # clojure-europe (23)
- # clojure-nl (3)
- # clojure-norway (2)
- # clojure-spec (3)
- # clojure-uk (18)
- # clojurescript (49)
- # community-development (1)
- # cursive (4)
- # datahike (2)
- # datascript (3)
- # datomic (36)
- # deps-new (2)
- # emacs (2)
- # events (9)
- # fulcro (6)
- # graphql (2)
- # gratitude (13)
- # holy-lambda (1)
- # introduce-yourself (10)
- # macro (2)
- # malli (5)
- # meander (9)
- # news-and-articles (5)
- # nextjournal (1)
- # off-topic (32)
- # pathom (17)
- # pedestal (13)
- # polylith (4)
- # protojure (4)
- # reagent (4)
- # sci (27)
- # shadow-cljs (2)
- # show-and-tell (2)
- # specter (3)
- # tools-deps (7)
- # xtdb (16)
I’m copying the following code to cljs (from https://web3js.readthedocs.io/en/v1.2.11/web3-eth-contract.html#deploy):
myContract.deploy({
data: '0x12345...',
arguments: [123, 'My String']
})
.send({
from: '0x1234567890123456789012345678901234567891',
gas: 1500000,
gasPrice: '30000000000000'
}, function(error, transactionHash){ ... })
and I have:
6 (<p!
7 (.. contract
8 (deploy (clj->js
9 {:arguments [(-> db :creation :name)
10 (-> db :creation :name)]
11 :data (.-bytecode (js/JSON.parse resp))}))
12 (send (clj->js {:from "0xA599D39F794E7676b829BDbB4D5a2f5F8835C5ad"}) (fn [err tx-hash]))))
But when I add the send line and wrap with <p!, I get the following:
ioc_helpers.cljs:50 Uncaught TypeError: Cannot read property 'length' of null
at Object.toUtf8Bytes (utf8.js:180)
at StringCoder.encode (string.js:25)
at eval (array.js:64)
at Array.forEach (<anonymous>)
at Object.pack (array.js:58)
at TupleCoder.encode (tuple.js:37)
at AbiCoder.encode (abi-coder.js:87)
at require.encodeParameters (index.js:121)
at eval (index.js:439)
at Array.map (<anonymous>
and ideas how to fix this and what’s causing this? It’s sad that the cljs compiler doesn’t tell you what’s wrong at the cljs levelI don't know what length refers to
There's no length in the code
Specifically in the send line
Which is where the error originates from apparently
(defn run-state-machine-wrapped [state]
(try
(run-state-machine state)
(catch js/Object ex
(impl/close! ^not-native (aget-object state USER-START-IDX))
(throw ex))))
throw ex is line 50Don't catch js/Object
, catch :default
.
Can't see anything useful here - go through the code that run-state-machine
calls. Or just break on caught exceptions in your browser. NodeJS debugger probably has a similar feature, if you're using that.
I didn’t write run-state-machine-wrapped
It’s part of the cljs source cljs.core.async.impl.ioc-helpers
what is the best way to (de/)serialize clojure/script code for transferring it over the wire and persisting it to disk?
If you have access to the code in its original form, then just send the text. If you only have some function or whatnot and want to serialize it, then it's impossible in the general case.
here is an example:
(cljs.tools.reader.edn/read-string (pr-str {:hello "world" :foo #"\a"}))
Execution error (ExceptionInfo) at (<cljs repl>:1). Unsupported escape character: \a.
You're using an EDN reader on something that's not EDN. Clojure code is a superset of EDN.
First, you need to amend your requirements then and make them accurate and precise.
Right now your OP says "transfer over the wire and persist to disk". You don't need any read
for that.
It's not readable by the EDN reader. It's readable by the LISP reader. clojure.core/read
.
Code is usually not transferred. And if you need to transfer it, then it is already in its perfect form - just text.
@U0P7ZBZCK How would an extra layer of encoding improve the situation?
it would be sensible to transfer code for certain systems such as smart-contract platforms. there you'd have libs for this very specific thing: serialization+deserialization of code
And as I mentioned already, you can't do it for the general case, only for some subsets of all the cases:
user=> (pr-str (java.util.concurrent.Executors/newFixedThreadPool 1))
"#object[java.util.concurrent.ThreadPoolExecutor 0x7dc51783 \"java.util.concurrent.ThreadPoolExecutor@7dc51783[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]\"]"
You can't read that #object
back it. Yes, you can create a parser for this particular class. But not for every class.Character encodings, and protocol encapsulation issues. If there’s a problem with pr-str just skip it completely
> Character encodings Right, but I assume UTF-8 text can be transferred without issues. > protocol encapsulation issues No idea what that means. > If there’s a problem with pr-str just skip it completely Exactly. That's what I meant by transferring code as regular text, if you have access to the original code itself.
Another fun example, among infinite, on why pr-str
has very limited usage:
user=> (pr-str #(inc %))
"#object[user$eval33$fn__34 0x3c443976 \"user$eval33$fn__34@3c443976\"]"
Not only the lambda is not in its original form - you can't even parse that line anymore. The data is lost.
So if you already have somewhere text that says "#(inc %)" - transfer that text. Don't try to evaluate it first, get the function object, then serialize that object, and then send it. Just send the text.
Also take a look at this example:
user=> (def x 1)
#'user/x
user=> (pr-str #(+ % x))
"#object[user$eval25$fn__26 0x30e92cb9 \"user$eval25$fn__26@30e92cb9\"]"
Same as above, only the lambda now closes over x
. You have to know about all such cases as well, and send (def x 1)
and all similar forms along.one could theoretically speaking have a smallest unit of meaningful code, such as a namespace and serialize within the confines of the namespace
If that ns is independent, I would just send the whole src/my/proj/ns.clj
file over the wire.
You still can't serialize evaluated objects, as I showed above.
> No idea what that means. I mean the protocol could be CSV or any other thing that could get tripped up by special characters in Clojure source code
When you use a protocol, usually you don't just give it data that's supposed to be preformatted. If you write a CSV via some library, generally that library will quote and escape all the special characters for you. Same how you don't compose HTTP messages by hand.
There are a couple of libraries designed to send serialized Clojure functions like this
But in general if you are asking this question, you’ll want to think really hard about whether this is the best idea
Just to add to the couple of libs Alex Miller posted, there's this one as well: https://github.com/helins/fdat.cljc