Fork me on GitHub
#clojurescript
<
2016-09-12
>
bill_tozier00:09:44

I’m having some trouble compiling a clojurescript app, apparently because of a conflict in the externs, and I’m not sure what the right approach is to fix things. I’m loading both highcharts and javascript as dependencies by adding them as :dependencies from cljsjs, but both extern.js files seem to define the $() function. Should I bring them into the project some other way, or should I try to munge the extern.js files somehow? As far as I know, I need them both as dependencies, since I’m using them to draw charts in reagent components. Any thoughts?

sreenath.n08:09:02

I am trying to setup google sign in button in my app. Here is the javascript code for the same

gapi.signin2.render('my-signin2', {
        'scope': 'profile email',
        'width': 240,
        'height': 50,
        'longtitle': true,
        'theme': 'dark',
        'onsuccess': onSuccess,
        'onfailure': onFailure
      });
How can I pass clojurescript function names as success and failure callback for this setup?

darwin08:09:39

(defn ^:export on-success [] …) and then reference it on-success, or by fully qualified name your.namespace/on-success

borkdude09:09:57

How can I install the cljs-devtools? The installation page is broken here. https://github.com/binaryage/cljs-devtools

borkdude09:09:32

where is that table again with clojurescript versions and what features it supports?

borkdude10:09:00

@anmonteiro I guess it was that one. Thanks!

borkdude12:09:38

core.cljs:53Uncaught Error: Assert failed: creagent$core$adapt_react_class @ core.cljs:53(anonymous function) @ react_util.cljs:11

borkdude12:09:43

anyone familiar with that one?

bill_tozier13:09:29

In the spirit of never asking a question and then keeping the answer secret: I was having a conflict between externs definitions from cljsjs/highcharts and cljsjs/jquery, and my production build would not compile. I was asking how to resolve the conflicts. The solution I came up with was: 1. change project.clj :dependencies to include [cljsjs/highcharts "4.2.5-1” :exclusions [cljsjs/jquery]] (not 100% sure why I excluded; better safe than sorry I think) 2. remove [cljsjs/jquery] dependency 3. load jQuery from the CDN in the template I suppose I need to ask how many JS dependencies really should ever be loaded from cljsjs….

bill_tozier13:09:39

@anmonteiro I will almost certainly end up bumping up against that as this prototype becomes a real product….

anmonteiro13:09:35

right, so the solution to that currently is to explicitly add one of the conflicting files to :foreign-libs in your build under a different name

samedhi14:09:57

I am going through http://clojure.org/guides/spec , really awesome. I have gotten to the point on generators and I am entering in my cljs repl (s/gen int?), however, I get

#object[Error Error: Var clojure.test.check.generators/simple-type-printable does not exist, clojure.test.check.generators never required]
Error: Var clojure.test.check.generators/simple-type-printable does not exist, clojure.test.check.generators never required
    at 

samedhi14:09:44

Anyone seen this error?

anmonteiro14:09:17

@samedhi you need to add clojure.test.check to your project and require it in that namespace

Alex Miller (Clojure team)14:09:33

there is a note to do that in the guide too :)

Alex Miller (Clojure team)14:09:10

I’m not 100% sure that step is identical in cljs though and would be happy to take a PR or pointer on how to improve it

samedhi14:09:50

I did fail to add it to the namespace (since this is clojurescript), let me give that a shot.

samedhi14:09:50

I added instead [cljs.spec.impl.gen :as gen]

Alex Miller (Clojure team)14:09:38

yeah, prob need to mention that

samedhi14:09:41

(:require cljs.pprint [cljs.core.async :as async :refer [<! timeout]] [cljs.spec :as s] [cljs.spec.impl.gen :as gen] [om.core :as om] [om.dom :as dom :refer [div video source track]] [om-tools.dom :include-macros true])

samedhi14:09:10

Compiles, but I get the above error when I try (s/gen int/)

anmonteiro14:09:36

@samedhi you still aren’t requiring clojure.test.check, AFAICT

samedhi14:09:51

@anmonteiro: Sad, I can’t believe I just did that twice.

samedhi14:09:04

Ok, got it past this point. Thank you all for your help.

samedhi14:09:14

Btw, this clojure.spec stuff is really cool.

darwin14:09:30

any example how to iterate native js array in a tight loop? loop is pretty close but I still have to use seq fist and next, would like to see it compiled into a javascript for loop

anmonteiro14:09:49

@darwin FWIW you can use seq, first and next/`rest` in JS arrays

darwin14:09:09

yes, that code already works for me, but I’m trying to optimize it to bare metal

darwin14:09:25

next step is .forEach

darwin14:09:37

but I would prefer an old-school for loop

anmonteiro14:09:39

re-reading the question, I didn’t understand it at first

curlyfry14:09:50

What are the plans for cljs.spec going forward? Slightly confused by the fact that spec is in alpha for JVM Clojure but in regular 1.9 for cljs. Will there be a point in time after (JVM) Clojure 1.9 is released and spec is finalized that clj.spec and cljs.spec will work the same (at least with regards to API)?

darwin14:09:30

just for context, I’m working on a library which will allow you to aget a path from nested #js objects, I generate static code when possible, but when I hit a dynamic case, I need to do it at runtime, and I want that routine to be as fast/low-level as possible

anmonteiro14:09:44

@darwin

cljs.user=> (def x #js [1 2 3])
#'cljs.user/x
cljs.user=> (while (pos? (.-length x)) (println "element: " (first x)) (.shift x))
element:  1
element:  2
element:  3
nil

anmonteiro14:09:46

maybe an option?

anmonteiro14:09:03

note that mutates the array

darwin14:09:52

good first step, I will use aget to index it directly without mutation, and avoid first, thanks

uwo17:09:28

we recently bumped our clojurescript version from 1.7.228 to 1.9.229. However, we found a change in behavior and I’ve narrowed down the change to the jump from 1.7.228 to 1.8.34:

anmonteiro17:09:47

oh that’s not in the gap you mentioned

uwo17:09:55

great. just wanted to make sure it was captured…. oh?

anmonteiro17:09:16

@uwo hrm I think that might be worth opening a JIRA ticket

uwo17:09:05

hm. ok. I’ve never made a ticket. I need to sign an agreement?

anmonteiro17:09:12

not for opening tickets

anmonteiro17:09:21

btw it seems related to get, not get-in

anmonteiro17:09:32

cljs.user=> (get "lol" nil)
"l"

anmonteiro17:09:19

@uwo hold on before opening a ticket, confirming one thing

uwo17:09:31

okie doke

anmonteiro17:09:14

OK go ahead, definitely a bug

anmonteiro17:09:36

(int nil) in a JS environment is 0 🙂

uwo17:09:51

heh. nice

anmonteiro17:09:59

@uwo happy to work on a fix tonight too

uwo17:09:32

@anmonteiro given https://github.com/clojure/clojurescript/wiki/Reporting-Issues, should I create a minimum reproduction, or would just a code snippet suffice?

anmonteiro17:09:57

@uwo don’t worry about that, just provide a description. I know what it is and will get to it tonight anyways 🙂

anmonteiro17:09:24

my code snippet above could potentially be a minimal repro if you want

uwo17:09:26

awesome. thx. jumping into a meeting atm, but will create it as soon as possible

uwo17:09:34

right. will do that

uwo19:09:41

@anmonteiro thanks for the help!

spiralganglion19:09:55

Hi guys. Hopefully simple question: I'm doing some HTML canvas drawing from CLJS. Let's say I have a vec of values, and I'd like to run a canvas lineTo(x,y) call for each entry in the vec, where x is the index and y is the value at that index. The vec might have tens of thousands of entries, and I'd like to do this drawing at 60fps, so perf is a bit of an issue. What would you suggest as the fastest way to run through the vec and call a side-effectful function for each entry?

spiralganglion19:09:46

I've played a bit with a while loop using an atom to track the current index (imperative af, I know)... and also using a map-indexed seq with dorun (which performs a little worse than the while loop).

spiralganglion19:09:21

For reference:

(dorun (map-indexed render-fn values)) ; Using dorun, or...
(while (< @i n-values) (render-fn @i (nth values @i)) (swap! i inc)) ; Using a while loop
I've stripped some unimportant details, so forgive any apparent weirdness. This is just to outline the two approaches.

spiralganglion19:09:10

@exupero I will try doseq. 1 sec.

spiralganglion19:09:49

I tried this:

(doseq [i (range) :while (< i n-values)] (render-fn i (nth values i)))

spiralganglion19:09:27

I don't think that's quite right, though..

spiralganglion19:09:51

Actually, that seems to work. But that has about the same perf as dorun — much (much) worse than while.

exupero19:09:01

Could probably also speed up while by using a volatile for i.

dreic19:09:18

I'm working on the modern-cljs tutorial and have a brepl running. Thing is, it doesn't evaluate my multi line input. Just "#_=>" after the last line. I'm here: https://github.com/magomimmo/modern-cljs/blob/master/doc/second-edition/tutorial-05.md#brepling-with-the-shopping-calculator and "1.00" doesn't appear.

spiralganglion19:09:45

@exupero Ah. Good idea. The swap call is the largest source of overhead to that approach. Also, when using doseq or dorun, there's about a 50ms GC pause every few seconds, which totally blows my 60fps 😞

exupero19:09:23

loop/`recur` also seems like a possibility.

jr19:09:27

@ivanreese you can try using a js array instead of vector and write a loop

spiralganglion19:09:24

Yeah.. dropping down to JS is my last resort. I'm using this as an opportunity to learn more about the perf characteristics of CLJS. I expect (hope) that there will be ways to "go fast" in CLJS, and I'm keen to find them.

dreic19:09:28

oh, now that I've copy/pasted it it works ...

dreic19:09:13

so I have to indent my code?

jr19:09:43

(loop [i 0]
  (when (< i n-values)
    (render-fn (aget values i))
    (recur (inc i))))

spiralganglion19:09:57

@exupero switching to while + volatile has seemingly made a sizeable improvement.

spiralganglion19:09:09

@jr I'll try loop/recur now

jr20:09:36

the trick for good performance will be allocating a js array (instead of vector) for the values and then loop using the aget operation on that js array

jr20:09:52

you can create a js array with (array) and aset the contents

spiralganglion20:09:11

Is there an equivalent to conj / push?

spiralganglion20:09:21

Or do I need to get the count, then aset?

spiralganglion20:09:53

I'm playing with this on the REPL and it seems count works, but I haven't found any other collection fns that do.

jr20:09:07

alength for the count

spiralganglion20:09:06

I wonder why (count my-js-arr) works..

spiralganglion20:09:27

(cond (array? coll) (alength coll))

wilkerlucio20:09:13

hello people, I'm trying to implement error reporting on my a node.js app, so I'm pushing the error object into a external service, the only problem now is that the stack goes into .js form, which is not that helpful. is there an way to source map stack traces for clojurescript on node.js?

tanzoniteblack20:09:27

@wilkerlucio as long as you’re enabling sourcemaps in your cljs build, then you should be able to use https://github.com/evanw/node-source-map-support to get node to be aware of them

tanzoniteblack20:09:18

(you can do it manually without that package if you need to as well, if so that package should be a good jumping off point on how to do it yourself)

wilkerlucio20:09:17

@tanzoniteblack: thanks for the feedback, I tried the node source map, but it doens't seems to be working, I added the package to my app, and added the .install command on the top of my execution, still seeing the old stack, did I missed something?

tanzoniteblack20:09:53

@wilkerlucio , you also verified that there is a sourcemap outputted by your cljsbuild, right?

tanzoniteblack20:09:10

(just covering basics, first)

tanzoniteblack20:09:24

and also did the

//# sourceMappingURL=path/to/source.map
bit to tell the library where your sourcemap is located?

spiralganglion20:09:29

@jr loop/recur seems about as fast as the volatile while loop — at this point, I'd need to disable some other parts of my system to really get a sense of how they compare. One curiosity: the render-fn was being created with partial (so that I could pass more arguments to it when it was being used with map-indexed). When I switched to loop/recur, performance absolutely cratered.. until I switched back to using the real fn, rather than the partially applied version. Looking at the call stack, it seemed the partial'd fn was being re-created on every loop!

wilkerlucio20:09:39

@tanzoniteblack yes, they are there. it seems that some portion is translated, I get stacks like these (even before using the node-source-map-support package):

anmonteiro20:09:46

@uwo attached a patch to your issue. Could potentially be included in the next version of ClojureScript

uwo20:09:43

excellent! thx anmonteiro

jr21:09:01

@ivanreese you’re right about partials. They are very slow in a tight loop

akiva21:09:02

I know that anonymous functions are better there but isn’t it even better to create the function outside of the loop and just call it?

spiralganglion21:09:07

The call to partial was outside the loop.

spiralganglion21:09:39

(let [render-fn (partial render-history ctx)]
        (loop [i 0]
          (when (< i n-values)
            (render-fn i (aget values i))
            (recur (inc i)))))

spiralganglion21:09:08

That's a bit simplified — render-history takes a whole bunch of args. Looking at the implementation of partial, it seems if you're passing a lot of args, it ends up using apply and concat behind the scenes, so that might lead to the slowdown.

spiralganglion21:09:45

In any case, I only needed the partial when I was using seq-based loops. Since I'm going to stick with either the while+volatile+js-arr, or the loop/recur+js-arr.. I don't need the partial. It was just.. surprising.

akiva21:09:33

I’ve been drilling down and learning the details about performance so all of this is very interesting for me.

spiralganglion21:09:19

Cool. Yeah, it's going to be a big focus for me, since 90% of the work I do needs to run at 60fps. (games, simulations, procedural art/music, etc)

akiva21:09:16

Yeah, I imagine. I spent 13 years doing .NET and the solution there was mainly just to throw more hardware at it. Heh.

akiva21:09:18

And of course all the basic level stuff like knowing when to use sprocs vs. LINQ or writing good looping algorithms and such.

spiralganglion21:09:12

Yeah. I'm going to enjoy finding the right balance between (lovely) immutable CLJS, and (works fine, just not as delightful) mutable JS.

spiralganglion21:09:14

I'm sure there'll be some super tight-loop/low-level code that I won't be able to hoist up into CLJS-land. But if I can find ways to use the superpower of immutability to just utterly skip doing work that doesn't need to be done, that'd be the most ideal. Finding it.. will be the challenge.

spiralganglion21:09:40

My render times are now dominated by browser APIs rather than CLJS core fns. Thanks for the help @exupero, @jr, and @akiva!

akiva21:09:13

Best of luck!

jr21:09:32

I tend to use the cljs compiler as a source of inspiration for performance tips. Good luck!

spiralganglion21:09:59

Like, reading the output of the compiler? Or reading the source of the compiler?

jr21:09:07

source of the compiler

jr21:09:33

dnolen is very careful about optimizing critical compiler paths

spiralganglion21:09:46

Ah, yeah. I look forward to doing a lot of source-diving on CLJ(S). I'm just still getting a handle on the basics of the language.

akiva21:09:56

I really like being able to just pull up clojure.core and read the source for a function to understand how it works.