Fork me on GitHub
#clojurescript
<
2017-07-21
>
mfikes00:07:47

@chalcidfly Normally, the entire form is first transpiled to JavaScript. I suspect you could first run the analyzer, get the AST, extract the subform, and evaluate that in a target JavaScript environment, and replace it to form a new form.

mfikes00:07:48

For your particular example, a tricky bit is the fact that * is a macro, so macroexpansion will also come into play

mfikes00:07:34

The easiest way to see what the analyzer produces, IMHO, is to fire up Lumo or Planck, and evaluate (cljs.js/analyze-str (cljs.js/empty-state) "(+ 2 (* 5 5))" nil {:eval cljs.js/js-eval :context :expr} identity)

chalcidfly01:07:57

@mfikes thanks for the reply — I’m not quite sure how to make sense of this. From the AST, how could I target a specific form?

chalcidfly02:07:21

The output is quite long even for that small example. Are there helper functions or will I just be calling keywords on it?

dpsutton04:07:55

@chalcidfly do you need to execute arbitrary clojurescript expressions or are they limited to just arithmetic?

dpsutton04:07:24

what i'm thinking is do you need to solve a quite possibly really impossible general problem or could you make an interpreter of a subset of the language

chalcidfly13:07:47

@U11BV7MTK my goal is to do arbitrary evaluation of Clojure forms

chalcidfly13:07:39

I was hoping there are methods available in cljs somewhere so that it wouldn't involve rewriting any of the interpreter

chalcidfly13:07:04

But I guess it would have to be sort of a fork of the interpreter? Just cutting the process short after a single form eval, and then converting from the AST back to a clojure form

dpsutton04:07:25

in common lisp this would be` (caddr (read-from-string "(+ 2 (* 5 5))"))`

Jon08:07:56

anyone got interested to look into this function here http://repo.tiye.me/gist/investigate-fipp/ ? I found it's slow, but don't know where is the slow code

Jon08:07:26

this is the graph I currently have

thheller09:07:28

@jiyinyiyong pretty printing in general is slower than normal printing, why do you need pprinted output? it doesn’t look like something a user would look at?

thheller09:07:11

can’t tell anything from your example other than it does a whole bunch of work

rauh09:07:44

@jiyinyiyong There is no easy/obvious part that is causing this slow runtime. You'll likely need to get into fipp and tune it to get it faster. I'd start with: Avoiding the seq-reduce and make it so it uses the normal (fast) reduce of the passed data structure. Not sure how easy it is, or if it's possible at all. That'd also improve on the GC problems.

rauh09:07:33

Also figure out that anonymous function at the top, and give it a name.

Jon09:07:55

@thheller I still want the file to be readable, if it can't, I have to give up.

Jon09:07:32

@rauh so, there's not an easy answer...

rauh09:07:40

I checked, but no, there is no low hanging fruit. Though, it doesn't look too difficult to make it fast in cljs.

Oleh K.12:07:27

Hi guys! How can I rewrite this function with spawn instead of exec? I tried but got ENOENT errors

(defui build-configuration [this]
  [:button {:type "button"
            :style {:margin-left 15}}
   "Build"]
  :click #(do
            (when (:builder @state)
              (kill-process (:builder @state)))
            (let [builder (.exec child-process (str "cd " (:path @this)
                                                    (if (= (:build @this) "dev")
                                                      (str (if (= (:platform @this) "android")
                                                             " && adb reverse tcp:8081 tcp:8081 && adb reverse tcp:3449 tcp:3449"
                                                             "")
                                                           " && re-natal use-" (:platform @this) "-device " (:device @this)
                                                           " && re-natal use-figwheel && lein figwheel " (:platform @this))
                                                      " && lein prod-build")))]
              (-> (.-stdout builder)
                  (.on "data" (fn[data]
                                (println data))))
              (-> (.-stderr builder)
                  (.on "data" (fn[data]
                                (println data))))
              (swap! state assoc :builder builder))))

Oleh K.12:07:18

The problem is that exec is unkillable.

jpmonettas13:07:37

Hi everybody! I'm having some trouble using clojure.pprint and cljs.pprint in a cljc file

jpmonettas13:07:11

when I use (pp/print-length-loop ...) it uses the clojure macro instead of the cljs macro

moxaj14:07:17

@jpmonettas 1. I'm pretty sure you don't need a reader conditional for that, clojure.pprint will be auto aliased to cljs.pprint

moxaj14:07:22

2. are you using self-hosted?

mfikes14:07:36

I can’t repro ^

mfikes14:07:47

@jpmonettas What evidence do you see that you are getting the Clojure macro?

mfikes14:07:54

To @moxaj’s 1st point, since ClojureScript 1.9.198, you can instead start writing:

(:require [clojure.pprint :as pp]))

jpmonettas14:07:55

@mfikes @moxaj the evidence is that it cant find level-exceeded var

jpmonettas14:07:53

which is a fn I think inside the clojure expanded macro

mfikes14:07:47

Is the code above in a namespace being required from ClojureScript as a macros namespace?

mfikes14:07:07

A minimal repro would help. (Perhaps the code and its usage in a gist.) @jpmonettas

jpmonettas14:07:47

yeah sure, I'm trying to move to cljs a lib I have for pprinting spec forms

jpmonettas14:07:57

I'll paste the link here

jpmonettas14:07:03

there is only that file

jpmonettas14:07:38

thx for looking at it @mfikes

jpmonettas14:07:15

but for making this kind of lib, is the idea to just require clojure.pprint

jpmonettas14:07:47

or do I need the reader conditionals and the require-macros?

mfikes14:07:12

I tried loading your minimal repro code and it failed with

cljs.user=> (require 'pretty-spec.core)
clojure.lang.ExceptionInfo: recur argument count mismatch at line 71 /Users/mfikes/Desktop/src/pretty_spec/core.cljc {:file "/Users/mfikes/Desktop/src/pretty_spec/core.cljc", :line 71, :column 4, :tag :cljs/analysis-error}

jpmonettas14:07:04

yeah couldn't figure out why that works on clojure but not in cljs

mfikes14:07:19

@jpmonettas What you do in your ns form depends on what versions of ClojureScript you want to support. (If you lib is to be used widely, and you want to support older ClojureScripts, then your approach might be better.)

mfikes14:07:26

One thing I noticed in your code is that you refer print-length-loop but appear to always use it qualified via the pp alias.

jpmonettas14:07:05

yeah sorry I was in the middle of changing that when I pushed

jpmonettas14:07:24

trying to figure out how to implement that so it's compatible

mfikes14:07:23

Even on older versions of ClojureScript, there is no need to :require-macros on cljs.pprint because it requires its own macros

mfikes14:07:18

(This is referred to as Implicit macro loading in the docstring for ns.)

jpmonettas14:07:44

so if I just requiring [clojure.pprint :as pp] the compiler complains about WARNING: Use of undeclared Var cljs.core/push-thread-bindings at line 69 src/pretty_spec/core.cljc WARNING: Use of undeclared Var cljs.core/var-get at line 69 src/pretty_spec/core.cljc WARNING: Use of undeclared Var cljs.core/pop-thread-bindings at line 69 src/pretty_spec/core.cljc

jpmonettas14:07:09

I think they are on clj pprint

mfikes14:07:11

This is with your current repro, but changing the ns form to be just

(ns pretty-spec.core
  (:require [clojure.spec.alpha :as s]
                  [clojure.pprint :as pp]))

jpmonettas14:07:58

but it somehow makes sense

mfikes14:07:04

I still can’t load your source due to the recur count issue

mfikes14:07:19

Did you revise something in the code?

jpmonettas14:07:40

thats weird that's the only change I have

jpmonettas14:07:37

I just pushed everything and this is what I'm doing to compile lein cljsbuild once Compiling ClojureScript... Compiling "target/main.js" from ["src"]... WARNING: Use of undeclared Var cljs.core/push-thread-bindings at line 69 src/pretty_spec/core.cljc WARNING: Use of undeclared Var cljs.core/var-get at line 69 src/pretty_spec/core.cljc WARNING: Use of undeclared Var cljs.core/pop-thread-bindings at line 69 src/pretty_spec/core.cljc Successfully compiled "target/main.js" in 4.9 seconds.

mfikes14:07:53

@jpmonettas Try reverting back down to using ClojureScript 1.9.660. I think you are seeing a bug in 1.9.671. Looking up the ticket…

jpmonettas14:07:12

yeah now it compiles

jpmonettas15:07:26

thx a lot @mfikes, I still haven't figured out the recur argument count but now it compiles ok

mfikes15:07:52

@jpmonettas I think I was vaguely thinking of CLJS-2069 as your problem, but it is evidently not. It also appears your problem occurs on master, so I’d suggest filing a regression JIRA.

devth15:07:18

maybe i'm reading this wrong. https://dev.clojure.org/jira/browse/CLJS-1800 says fix version is 1.9.671 but that version was released 21 days ago and the actual patch that fixed it was applied 13 days ago. doesn't compute.

rauh15:07:15

@devth The JIRA tags are often not correct

bbloom16:07:25

@jiyinyiyong the demo with profiling is helpful. thank you. it looks like the bounded-count routine is a little slow on cljs, i will look at it more closely

bbloom16:07:29

hmm, this looks like a performance regression in CLJS

bbloom16:07:03

fipp makes a lot of use of apply

bbloom16:07:14

well not really - indirectly

bbloom16:07:01

i made a performance/design mistake that i’m stuck with in vim to treat text and pass nodes as variadic

anmonteiro16:07:01

@bbloom apply should be much faster in 1.9.671, which version are you trying?

bbloom16:07:56

bounded-count shows up on the stack trace a lot with a ton of seq allocation

anmonteiro16:07:28

Oh hrm, no console on mobile

anmonteiro16:07:34

I'll take a look later

bbloom16:07:47

i’m not sure what version of cljs it is

anmonteiro16:07:33

Perhaps there's a _STAR_clojurescript_version_STAR_ in there

rauh16:07:49

@anmonteiro Already checked, got compiled out

rauh16:07:18

The bounded count is part of apply. And it's used b/c of the lazy seq's. Can you do the transformations non-lazy @bbloom ?

bbloom16:07:19

yeah, was jus tlooking for it 🙂 when @jiyinyiyong returns, maybe he can let us know & try 1.9.671 or newer

anmonteiro16:07:13

I think doing non-lazy transformations in Fipp would result in it not being memory-bound anymore

rauh16:07:19

It's 1.9.671 by checking the source map.

bbloom16:07:48

@rauh not really - the only way to go non-lazy would be to use concurrency primitives, which would be even slower

rauh16:07:54

My apply optimizations don't kick in when calling variadic fn's. So there is no gain with the new version.

bbloom16:07:24

the serialize function produces a command sequence, but it relies on laziness to prevent realizing the full document in memory

rauh16:07:36

I do have more apply optimizations in the pipeline that also speed up this exact case, but it's not ready yet.

bbloom16:07:11

@rauh thank you. please elaborate. what’s “this exact case”, why is it slow, and how are you going to improve it?

rauh16:07:16

@bbloom I sped up apply for calling non-variadic fns (incl. mutli arity) but you seem to be calling mostly variadic fn's with apply, which is still kinda slow (not that slow actually).

bbloom16:07:31

@rauh seems like the bounded-count makes it slower now

bbloom16:07:39

lots of calls to seq

rauh16:07:52

@bbloom The bounded count was always in the apply fn. That didn't change. But I do want to change it in the future to avoid it completely.

bbloom16:07:13

hm ok - i don’t really use fipp from cljs much, so i didn’t profile it extensively myself

bbloom16:07:20

i’m only looking at it now on behalf of @jiyinyiyong

rauh16:07:46

@bbloom This is easy to speed up in cljs: (apply str (repeat indent \space)))

bbloom16:07:06

@rauh i’m working off memory here, but isn’t repeat a efficient reducable? that shouldn’t allocate a seq at all, right?

rauh16:07:25

@bbloom Correct in CLJ, not so in CLJS.

rauh16:07:47

(defn repeat
  "Returns a lazy (infinite!, or length n if supplied) sequence of xs."
  ([x] (lazy-seq (cons x (repeat x))))
  ([n x] (take n (repeat x))))

bbloom16:07:09

“easy to speed up in cljs” - the compiler? or by changes to fipp?

bbloom16:07:28

compiler/lib

rauh16:07:32

Changes to fipp. Just do a (.join (make-array 10) " ")

bbloom16:07:18

fipp’s engine is cljc, there has never been platform specific code in it - i don’t want to start now if i can help it

bbloom16:07:59

presumably repeat can be optimized in cljs itself?

bronsa16:07:11

@bbloom apply doesn't use reducibles anyway

bbloom16:07:00

ok, still not even sure it really matters, since that’s far from the bottleneck vs the serialization routines, which are much more allocation and apply heavy according to profiles

bbloom16:07:09

also, i’m not even sure this is an issue, as fipp is still quite fast for iteractive use

bbloom16:07:36

@jiyinyiyong does some crazy stuff with a crazy custom projectional non-text editor he wrote and pretty prints things, so his needs are bigger

bbloom16:07:19

i had a little spare time between meetings this morning, so i figured i’d look at this - if ppl who actively work on the cljs compiler/runtime need a good test case for improving the seq/bounded-count/apply codepath, i’m happy to help via insights in to fipp

bbloom16:07:59

thanks all 🙂

jpmonettas17:07:34

@bbloom fipp is great, just discovered it and I'm moving all my clojure.pprint code to fipp documents

jpmonettas18:07:40

how do you dispatch on sequences in multimethods given that (isa? cljs.core/List cljs.core/ISeq) => false ?

akiroz18:07:45

@jpmonettas

(defmulti foo
  #(or (list? %) (seq? %)))
(defmethod foo false [not-seq]
  ...)

devth20:07:57

can you alias functions and make it so they won't get munged by advanced compilation?

devth21:07:17

e.g. a few top level util functions that i could use to poke around in a deployed app

devth21:07:41

guessing it must be part of a namespace, so i could create a simple namespace then add them all to an externs file. is that it, or is there an easier way?

anmonteiro21:07:59

(defn ^:export myfn ...?

devth21:07:15

nice. i wasn't aware of that capability

devth21:07:41

does that put it under window or its namespace?

devth21:07:47

looks like it keeps it under its ns.