clojurescript

ClojureScript, a dialect of Clojure that compiles to JavaScript http://clojurescript.org | Currently at 1.10.879
Endre Bakken Stovner 2021-05-17T07:45:57.026100Z

I am getting the following errors from https://github.com/endrebak/everclear/blob/working/src/cljs/everclear/dag/core.cljs, the most important of which I guess is

react-dom.development.js:68 Warning: React has detected a change in the order of Hooks called by everclear.dag.core.graph_page. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: <https://reactjs.org/link/rules-of-hooks>

   Previous render            Next render
   ------------------------------------------------------
1. useState                   useState
2. useRef                     useRef
3. useEffect                  useEffect
4. undefined                  useState
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
Any hints on how to debug?

thheller 2021-05-17T07:50:48.027Z

@endrebak85 hooks have very specific rules. you must move the useState call into the inner fn or remove that inner fn entirely

thheller 2021-05-17T07:51:48.027600Z

also your use of those hooks is incorrect. you definitely should not be calling set-graph as part of the render

Endre Bakken Stovner 2021-05-17T07:53:39.028800Z

Hmm, I guess the set-graph can just be in a function of its own that listens to the sub since it does not need to add any hiccup, it just modifies an existing element. Thanks. Will try some more.

thheller 2021-05-17T07:56:14.030300Z

you are trying to mix 2 entirely different rendering models. so you must read up on refs in react and them use them in a useEffect hook to wire up the graph stuff

thheller 2021-05-17T07:56:54.030700Z

or go without hooks and just refs, that is fine too

thheller 2021-05-17T07:59:24.031800Z

the when-let is a problem as well. if the subscribe returns nil on the first try it'll never update if it becomes available later

Endre Bakken Stovner 2021-05-17T08:07:04.031900Z

Thanks. I was just copying the luminus template which uses the following:

(defn page []
  (if-let [page @(rf/subscribe [:common/page])]
I thought it was a way to postpone the showing page until the data was ready.

thheller 2021-05-17T08:10:14.032200Z

does that have the inner anon fn? I guess not?

Endre Bakken Stovner 2021-05-17T08:13:29.032400Z

No πŸ™‚

Endre Bakken Stovner 2021-05-17T08:21:21.032600Z

Thanks. I did not know I was mixing them πŸ™‚ Now I've gotten it to work with refs.

Endre Bakken Stovner 2021-05-17T11:22:25.036300Z

I am trying to translate the following code into ClojureScript (the javascript is a simplified version of https://github.com/ArquintL/d3-dag-example/blob/master/src/app.js):

const reader = d3_dag.dagStratify()
const dag_data = await d3.json(`<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>`);
reader(dag_data)
This is my attempt:
reader (d3-dag/dagStratify.)
data (-&gt;
      (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>")
      (.then reader)) // failing line
I get the error:
Uncaught Error: can't stratify empty data
Am I doing something obviously wrong in my handling of https://clojurescript.org/guides/promise-interop or what?

niwinz 2021-05-17T11:25:29.037700Z

On the js side you don't calling new on dagStratify(), so in cljs you dont need to use the . in (d3-dag/dagStratify.)

Endre Bakken Stovner 2021-05-17T11:33:18.038900Z

Thanks, that seemed to do it πŸ™‚

Endre Bakken Stovner 2021-05-17T12:09:33.042400Z

This is the first time I have to use go-blocks and the first time I've had to deal with promises, so I am a little confused. If I want to translate the following into a go-block, how would I do it?

const reader = d3_dag.dagStratify()
const dag_data = await d3.json(`<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>`);
reader(dag_data).then(d3_dag.sugiyama())
I've gotten this far:
(let [reader (d3-dag/dagStratify)
          sg (d3-dag/sugiyama)
          dunno? (go
                   (let [data (&lt;p! (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>"))
                         dag-data (reader data)
                         layout (&lt;p! (sg dag-data))]
                     layout))]
I think everything but layout (&lt;p! (sg dag-data)) is correct. But I am having a hard time translating this call:
reader(dag_data).then(d3_dag.sugiyama())

thheller 2021-05-17T12:36:58.043200Z

@endrebak85 don't waste your time on a go block for this, just chain the promises

(-&gt; (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>")
    (.then reader)
    (.then (d3-dag/sugiyama)))

πŸ‘ 1
πŸ™ 1
Chris Lowe 2021-05-17T12:43:28.043300Z

from the gist:

loadDag(source)
  .then(useArquint ? arquint() : sugiyama())
  .catch(console.error.bind(console));

async function loadDag(source) {
  const [key, reader] = sources[source];
  const dag_data = await d3.json(`<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/${key}.json>`);
  return reader(dag_data);
}
It looks like loadData also returns a Promise (based on the immediate call to .then()). The last line of loadData is reader(dag_data) so your code equivalent of this line would need its own (&lt;p!) call to yield the result:
(go
  (let [data (&lt;p! (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>"))
        dag-data (reader data)         ;; try wrapping in (&lt;p! ) 
        layout (&lt;p! (sg dag-data))]    ;; not sure if call to sg returns a promise? 
   layout))
…or chaining then calls might be cleaner.

πŸ‘ 1
Endre Bakken Stovner 2021-05-17T12:58:57.044100Z

Much obliged!

dnolen 2021-05-17T14:05:41.045600Z

though you probably want error handling

πŸ™ 1
dnolen 2021-05-17T14:06:01.046100Z

and then depending on how far away the error handling needs to be, or how many handlers there may need to be

dnolen 2021-05-17T14:06:10.046400Z

you may or may not want to do this w/ promises

dnolen 2021-05-17T14:06:36.046800Z

but if it's not involved I agree chaining is fine

dnolen 2021-05-17T14:13:11.048Z

I much prefer go + try/catch + ex-info + causes

Endre Bakken Stovner 2021-05-17T15:03:01.053800Z

I want to call the .links function on the object in a promise. I think I've tried every variation of the below, but nothing works

(.then graph.links) ;; (-&gt; graph (.then (.links)) ;; ...
What is the correct way to do it? Below the promise-wrapped graph object is shown. It has a .links method, but I do not know how to get at it.

thheller 2021-05-17T15:03:59.054300Z

(.then (fn [obj] (do-stuff-with (.-links obj))) or rather (.links obj), looks to be a function

πŸ™ 1
Endre Bakken Stovner 2021-05-17T15:25:15.055800Z

Thanks. In https://github.com/ArquintL/d3-dag-example/blob/master/src/sugiyama.js#L76 I'm trying to convert it is a function, but when I try to use it as a function, I get the error: Uncaught (in promise) TypeError: obj.links is not a function. Any ideas what might be wrong?

dpsutton 2021-05-17T15:26:08.056300Z

console.log the item and see if it resembles what you expect

Endre Bakken Stovner 2021-05-17T15:28:45.057300Z

I have done so:

{dag: LayoutDagRoot, width: 5.83843708165997, height: 8}
dag: LayoutDagRoot
dagRoots: (6) [LayoutDagNode, LayoutDagNode, LayoutDagNode, LayoutDagNode, LayoutDagNode, LayoutDagNode]
__proto__:
...
links: Ζ’ links()
So it should have a link method AFAICS.

dpsutton 2021-05-17T15:29:32.057600Z

can you paste the exact code you are using to try to call it?

Endre Bakken Stovner 2021-05-17T15:30:17.058Z

Sure:

(.data (-&gt; graph (.then (fn [obj] (js/console.log obj) (.links obj)))))

dpsutton 2021-05-17T15:34:19.059Z

that looks quite different that .data(dag.links()) above. and you're sure links: f links() is on the top level and not nested in the obj you are logging?

thheller 2021-05-17T15:35:36.059500Z

graph also probably isn't a promise? what is graph? maybe you just want (.data (.links graph))?

dpsutton 2021-05-17T15:37:44.060Z

yeah from that code sample there's no promise stuff going on

thheller 2021-05-17T15:37:53.060400Z

would help to have your full code, seems like you are making a couple mistakes

Endre Bakken Stovner 2021-05-17T15:40:59.064Z

Rendering a DAG is about the only thing I need to do in JS so I have not started reading properly about JS/ClojureScript yet. I'd love to include a Clojure-project in my PhD, but I am working against a tight deadline, so I am just trying to get stuff to work quickly.

dpsutton 2021-05-17T15:41:02.064100Z

there's no use of then in the sample you are following. why did you introduce that

Endre Bakken Stovner 2021-05-17T15:41:43.065100Z

Because I could not find a .link function and I assumed it was because it was wrapped in a promise.

Endre Bakken Stovner 2021-05-17T15:43:21.065800Z

And if I try to log that graph, I am told it is a promise: [object Promise].

dpsutton 2021-05-17T15:44:26.067Z

so their dag is passed in. not sure how they got it, but perhaps they are calling (.then dag draw).

Endre Bakken Stovner 2021-05-17T15:45:31.068300Z

The data is loaded with d3.json which returns a promise so I guess whatever they do after that also happens in a promise.

Endre Bakken Stovner 2021-05-17T15:46:51.069900Z

But yeah, everything happens within a .then: https://github.com/ArquintL/d3-dag-example/blob/master/src/app.js#L18 That sugiyama function is what contains all the calls.

dpsutton 2021-05-17T15:47:48.070600Z

so their function takes the value resolved from a promise, but you are passing that promise in. you'll need to correct that

Endre Bakken Stovner 2021-05-17T15:51:23.073800Z

I thought once a promise always a promise. I looked for a way to unpack/deref a promise, I guess this is it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve

thheller 2021-05-17T15:52:56.074700Z

no, you (.then render-graph). the variable you named dag is actually the dag promise, so the only way to get the actual dag is to .then it and access it async

anonimitoraf 2021-05-17T15:54:54.075400Z

There's also the &lt;p! macro in cljs.core.async for 'awaiting' Promises AFAIK (tagged experimental though)

anonimitoraf 2021-05-17T15:55:50.076200Z

https://clojurescript.org/guides/promise-interop

thheller 2021-05-17T15:58:22.077100Z

(defn render-graph [data]
  ...)

(defn graph-page []
  (-&gt; (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>")
      (.then render-graph))
  [:div
   [:h1 "hiya"]])

thheller 2021-05-17T15:58:48.077800Z

this is still widely incorrect regarding the react use but at least in render-graph you don't have to worry about promises at all anymore.

Endre Bakken Stovner 2021-05-17T16:07:10.080400Z

Thanks all, now I am getting closer. I just need to find out how I'm mishandling react. Btw, this is for a project I'm hoping to publish in bioinformatics (or at least biorxiv) by the end of the year. I will discuss Clojure in it too. What channel would be most appropriate for asking about feedback on my discussion/summary of Clojure?

Endre Bakken Stovner 2021-05-17T16:10:50.080500Z

Thanks. I should learn more about &lt;p! too πŸ™‚

dpsutton 2021-05-17T16:12:55.081200Z

if it's a general "about clojure" type thing, probably off-topic. if you write an article there's an #news-and-articles channel as well

πŸ™ 1
Endre Bakken Stovner 2021-05-17T16:29:03.084300Z

I cannot find any documentation about the use of curlybraces below (taken from here: https://github.com/ArquintL/d3-dag-example/blob/master/src/sugiyama.js#L102):

({x, y}) =&gt; `translate(${x}, ${y})`)
;^^^^^
What is the correct way to translate this? In a node repl, that function does not seem make sense, but I might be invoking it incorrectly:
&gt; var f = ({x, y}) =&gt; x + y
undefined
&gt; f(1, 2)
NaN

Endre Bakken Stovner 2021-05-18T09:28:27.005900Z

Thanks. Weird that googling "anonymous function js curly braces" returned nothing relevant

thheller 2021-05-18T09:30:34.006100Z

really not specific to anonymous function in any way

πŸ‘ 1
thheller 2021-05-18T09:30:43.006300Z

let {x, y} = obj; is also valid

thheller 2021-05-17T16:31:33.085400Z

this is destructuring for a JS obj, can't do that in CLJS. but (fn [obj] (let [x (.-x obj) y (.-y obj)] ...)) works

πŸ™ 1
localshred 2021-05-17T16:57:42.085600Z

In JS that's destructuring a single object argument to get keys x and y from the object and bind them as local vars to the same names as the keys

localshred 2021-05-17T16:57:51.085800Z

So in JS you'd call f like this:

localshred 2021-05-17T16:58:12.086Z

f({x: 123, y: 456})

localshred 2021-05-17T16:59:14.086500Z

cljs has clojure map destructuring in the argslist, but unfortunately (as @thheller points out) you can't destructure a JS object in cljs in the argslist, you'll have to bind it to a local arg name and pull out those values yourself

localshred 2021-05-17T17:00:47.086800Z

an equivalent non-destructured JS implementation of f is

localshred 2021-05-17T17:01:09.087Z

const f = (obj) =&gt; obj.x + obj.y

Nathan Tuggy 2021-05-17T19:18:42.089600Z

I’m starting a REPL with clj -M --main cljs.main --repl and using Firefox (88.0.1 on Mac) as my default browser, but the REPL immediately freezes as soon as I try to evaluate anything at all, and I can only quit it by Ctrl-C (not Ctrl-D). Deps.edn only has ClojureScript 1.10.844, nothing else. This hang doesn’t happen with Chrome, but what’s wrong with ClojureScript in Firefox?

dnolen 2021-05-17T19:28:46.089900Z

@ntuggy just tried with 88 no issues

dnolen 2021-05-17T19:29:14.090200Z

and 88.0.1 as well

Nathan Tuggy 2021-05-17T19:35:42.091800Z

Thanks for checking. Any ideas on figuring out where the problem is? Nothing shows up in the browser console, even in Safe Mode. (Also, it’s not just Firefox; I started with Pale Moon, a Firefox fork, and only switched thinking it might be some obscure compatibility bug.)

dnolen 2021-05-17T19:39:58.092400Z

hrm I really don't know - something environmental for sure

dnolen 2021-05-17T19:40:24.093100Z

if you just need/want to dev ClojureScript this doesn't seem essential

dnolen 2021-05-17T19:41:36.094500Z

i.e. dev in Chrome - test all browsers (no REPL)