Fork me on GitHub
#clojurescript
<
2018-03-08
>
Wilson Velez01:03:57

Hi, is there a uri predicate for clojurescript?

joshkh08:03:51

is support for node modules normally compatible with figwheel's hot reloading?

joshkh09:03:37

whoops, problem solved by upgrading figwheel from 0.5.11 to 0.5.15

sandbags11:03:20

This is maybe kind of crazy but has anyone tried using ClojureScript as the scripting language for a Mac app? I'm building a Mac Cocoa app and have resigned myself to using JavascriptCore as the scripting engine since its out of the box and they make the integration laughably easy. But I grimace slightly at the idea of using the language. I wondered how plausible it might be to actually use ClojureScript in there.

manutter5112:03:36

I can’t answer your question directly, but if I were trying to implement an in-app scripting language for Cocoa, my first stop would definitely be to have a look at planck https://github.com/mfikes/planck

sandbags11:03:16

I'm not sure if what i have in mind is trivially simple or incredibly complex

genRaiy11:03:44

shadow-cljs … does anyone (ok does @thheller) know how to watch test files and have them run automagically?

genRaiy11:03:22

*automagic = when I save a file

thheller11:03:35

@raymcdermott chokidar 'out/test.js' -c 'node out/test.js' via https://github.com/kimmobrunfeldt/chokidar-cli

thheller11:03:23

I have something in the works so you don't need external tools but its going to take a bit of time till its done

genRaiy11:03:23

I can wait a little while … just wanted to make sure that I wasn’t missing some existing feature

thheller11:03:28

also there is #shadow-cljs

genRaiy11:03:00

ah … ok I’ll go there for these question - sorry to bother others here

mfikes14:03:35

I’ve you’ve been trying the ClojureScript pre-release train, beta 1.10.145 is available now. Give it a shot, nearly all bugs have been addressed and it very close to release now!

dnolen14:03:15

@sandbags I’m pretty sure @mfikes has tried that before, macOS w/ ClojureScript?

mfikes14:03:33

Hmm. There is this failed attempt https://github.com/mfikes/planck/issues/122 But, if you want to just script up reading and writing files, Planck is already set up to drive the JavaScriptCore that ships with macOS.

dnolen14:03:57

@mfikes what about Ambly?

mfikes14:03:57

Yeah, Ambly could be used to drive any macOS app that embeds JavaScriptCore, and that app can do anything (drive JavaScript for Automation, perhaps)

borkdude14:03:38

Say, I have a macro in a cljc file that I want to call from a cljs file. 1) Does the macro have to be in a reader conditional block? 2) Do I use refer-macros or plain refer in cljs for referring macros from a cljc file? I had the macro without a reader conditional and used refer. Sometimes we got error message (not on all machines). Changing the refer to refer-macros solved it. The macro was:

(defmacro ->map
  "(->map a b) ;;=> {:a a :b b}"
  [& symbols]
  (assert (every? symbol? symbols))
  `(hash-map
    ~@(interleave (map keyword symbols) symbols)))
and the error we sometimes got is from the assert. But not always, sometimes it just worked. Example call:
(->map a b) ;;=> {:a a :b b}
When we changed :refer to :refer-macros it worked as expected.

moxaj14:03:43

@borkdude afaik, 1) no, 2) normally you'd use refer-macros, but if you're using a fairly recent version of cljs, you can use :refer with implicit macro loading (see https://gist.github.com/mfikes/40b634b1ef8e317d8d5a)

moxaj14:03:26

also, you'd have to wrap the :require-macros ... part in a reader conditional since that does not exist in clj

borkdude14:03:26

ok, but apparently this could still contain bugs, why else would switching from refer to refer-macros solve our problem…

borkdude14:03:47

require-macros is not in a cljc file, but in a cljs file

moxaj14:03:59

I mean in the context of the gist I linked

borkdude14:03:05

the macro itself is in a cljc file

borkdude14:03:47

I wonder if it makes sense having it not inside a #?(:clj ...) block though

moxaj14:03:24

it = the macro?

moxaj14:03:55

I think it compiles in both cases

borkdude14:03:19

if I don’t wrap it inside a conditional, it would be as if I also put it in a cljs file right…

mfikes14:03:22

@borkdude One thing that might help get to the bottom of it is to see how the ns forms desugar when you employ :refer-macros or :refer. But then again there is implicit infer behind :refer now.

mfikes14:03:49

One way to desugar is to use Lumo or Planck and "Desugaring in the REPL" at http://blog.fikesfarm.com/posts/2016-03-01-clojurescript-macro-sugar.html

mfikes14:03:39

@borkdude If you don't put the macro in a reader conditional, it won't matter to the JVM ClojureScript compiler: It loads that file and it is processed by Clojure

joshkh14:03:58

does anyone know what this tweet is referring to? i'm pretty curious. maybe something about interop and clojars? https://twitter.com/functionalcave/status/971438971648692225

borkdude14:03:35

@mfikes This is the desugared form:

(ns
 dre.ticker.events
 (:require
  [ajax.core :as ajax]
  [dre.api.articles.search :as asa]
  [dre.coll :refer [->map]]
  [dre.config :refer [config]]
  [dre.document-util :refer [new-article article->id]]
  [dre.search.query :as q]
  [dre.search.util :refer [normalized-blunt]]
  [dre.ticker.db :as db]
  [re-frame.core :as re-frame :refer [path reg-event-db reg-event-fx]]
  (taoensso.timbre))
 (:require-macros (taoensso.timbre :refer [info debug warn])))

borkdude14:03:55

This is the original one:

(ns dre.ticker.events
  (:require [ajax.core :as ajax]
            [dre.api.articles.search :as asa]
            [dre.coll :refer [->map]]
            [dre.config :refer [config]]
            [dre.document-util :refer
             [new-article article->id]]
            [dre.search.query :as q]
            [dre.search.util :refer [normalized-blunt]]
            [dre.ticker.db :as db]
            [re-frame.core :as re-frame :refer
             [path reg-event-db reg-event-fx]]
            [taoensso.timbre :refer-macros [info debug
                                            warn]]))

borkdude14:03:04

our cljs coordinates: [org.clojure/clojurescript "1.9.946"]

borkdude14:03:36

I have used Planck 2.9.0 (same cljs version) to evaluate this

mfikes14:03:41

@joshkh I have a strong hunch it is referring to the new ability of ClojureScript 1.10.x to cache artifacts compiled from code in JARs in a shared cache on your box (in ~/.cljs)

mfikes15:03:48

@borkdude Another hunch, perhaps some code is setting *assert* and the loading order affects whether it is enabled

borkdude15:03:47

does the desugared form look alright to you?

joshkh15:03:05

ah, neat! thanks for the hunch

mfikes15:03:11

Yeah, @borkdude it doesn't give me any more of an idea of what might be going on

mfikes15:03:11

The 1.10.x cache feature is nice because you can't put AOT ClojureScript artifacts in JARs (because they won't necessarily valid for all ClojureScript versions), so the shared AOT cache effectively solves that problem. Thus perhaps the tweet is showing ClojureScript 1.10.x "embracing" Clojars in a sense.

borkdude15:03:07

@mfikes The weird thing is that we didn’t get this as a compile time failure, but as a failure in the browser console:

router.cljc:203 Uncaught Error: Assert failed: (every? symbol? symbols)
    at Function.dre.coll.__GT_map.cljs$core$IFn$_invoke$arity$variadic (coll.cljc:563)
    at dre$coll$__GT_map (coll.cljc:560)
    at events.cljs:64
Normally when I do this: (->map "foo") I get a compile time assert error, not something from the browser console

borkdude15:03:12

that’s why I thought maybe putting the macro itself in a #?(:clj ...) block would help

borkdude15:03:41

How can a compile time assert leach into the browser logs

mfikes15:03:00

Are you using self-hosted ClojuresScript at all?

mfikes15:03:52

Or perhaps ->map is being compiled to a runtime function... making it into your JavaScript, and :refer-macros forces the issue, making it be treated as a macro

mfikes15:03:31

Perhaps macro inference is failing if you :refer [->map]. Is there a ->map function in the runtime namespace?

borkdude15:03:50

do you mean in cljs or clj?

mfikes15:03:51

It looks like there is a dre.coll/->map in a .cljs file

borkdude15:03:36

how did that get there..

mfikes15:03:24

Ahh, if you (:require [dre.coll :refer [->map]]) and it is in a .cljc file then it will be processed as ClojureScript

mfikes15:03:04

You can fix that though, I think. If you add a coll.cljs file that does nothing more than :require-macros on itself.

borkdude15:03:08

even if it’s a defmacro ?

mfikes15:03:32

Yes, the file is being loaded as a ClojureScript file by :require

borkdude15:03:02

and if I wrap ->map in a conditional #?(:clj ...)?

mfikes15:03:46

If you wrap it with #?(:clj ...) then it won't be available at all (not as a function nor a macro)

mfikes15:03:05

By adding a core.cljs you are enabling Implicit macro loading as described in (doc ns)

borkdude15:03:54

what is odd is that it used to work for months. we changed some unrelated part of our code base and this popped up

mfikes15:03:26

Or, @borkdude just change the file to be a .clj file

borkdude15:03:57

yeah, but we do have a bunch of shared code in there

mfikes15:03:02

By having it sitting there by itself as a .cljc file, it is all to easy for it to be eligible for processing as a runtime ClojureScript namespace

mfikes15:03:40

Oh, is it a mixture of runtime and compile-time stuff?

borkdude15:03:20

Maybe I should look at https://github.com/cgrand/macrovich for this problem?

mfikes15:03:32

Yep, I was thinking of exactly that.

borkdude15:03:33

and I can also use the implicit cljs solution

mfikes15:03:06

If you add a .cljs file, then it would break code that wants to load the .cljc file as ClojureScript.

borkdude15:03:10

complex situation 🙂

souenzzo15:03:25

Trying the new 1.10.145: when I build (with figwheel)

Figwheel: Starting server at 
Figwheel: Watching build - dev
Compiling build :dev to "resources/public/javascript/main.js" from ["src" "test" "dev"]...
WARNING: preload namespace user.cljs does not exist
Successfully compiled build :dev to "resources/public/javascript/main.js" in 11.747 seconds.
On repl
=> nil
(require '[user.cljs])
ClojureScript 1.10.145
=> nil
(in-ns 'user.cljs)
ClojureScript 1.10.145
=> nil
(dir user.cljs)
ClojureScript 1.10.145
----  Compiler Warning on   <cljs form>   line:1  column:2  ----

  Use of undeclared Var user.cljs/dir

  1  (dir user.cljs)
      ^--- 

----  Compiler Warning  ----
#object[TypeError TypeError: user.cljs.dir is undefined]
=> nil
(user.cljs/on-js-reload) 
ClojureScript 1.10.145
=> #object[HTMLDivElement [object HTMLDivElement]]
Really odd

souenzzo15:03:01

user.cljs is on dev/user/cljs.cljs

mfikes15:03:39

@souenzzo Sounds like a minimal repro is possible

dnolen16:03:43

this doesn’t look like a bug

dnolen16:03:11

unless I’m forgetting, REPL requires are not auto imported into other namespaces

sandbags15:03:03

At first glance Ambly looks like exactly what I want

sandbags15:03:03

a ClojureScript REPL and the ability to call clojurescript functions from Cocoa and vice-verca

sandbags15:03:39

running inside JavascriptCore

borkdude15:03:15

@mfikes if I understand the macrovich docs right, putting my macro inside a macros/deftime would solve my problem right?

borkdude16:03:22

#{@mfikes, @cgrand} why would cljs compile a macro in a cljc file to a function though?

cgrand16:03:18

my guess: because it’s useful for selfhost, but shouldn’t happen for “regular” cljs

cgrand16:03:40

and m/deftime should hide it from run time

mfikes16:03:40

Right; there was discussion of making the compiler balk, but it wasn't deemed necessary to prevent that

borkdude16:03:48

I would still like that. This is very confusing…

mfikes16:03:58

Write a JIRA 🙂

borkdude16:03:47

is there a way to refer to this conversation from JIRA?

cgrand16:03:13

copy & paste before slack oblivion

borkdude16:03:09

k, thanks you two!

mfikes16:03:33

But, a repro is pretty simple, you just want (defmacro foo []) to fail in ClojureScript code (in a cljs file, or in a REPL, or in a cljc file not being processed as a macro namespace)

mfikes16:03:46

There are interesting things that are allowed in self host, this one for example https://dev.clojure.org/jira/browse/CLJS-2015

borkdude16:03:24

@cgrand what does [net.cgrand.being :refer [add]] refer to?

cgrand16:03:17

@borkdude good catch, I fixed the README

cgrand16:03:03

does it make sense now?

borkdude16:03:08

@cgrand yes, working on it

borkdude16:03:36

@cgrand works like a charm now. What is use case for usetime, this is not clear to me from the docs. What problem does it solve? Example would help.

cgrand17:03:11

it solves 2 problems:

cgrand17:03:12

1/ in cljs/clj, avoiding some cljs code to be compiled by clj (can be solved by a reader conditional) 2/ in cljs/cljs avoiding double compilation (between the real namespace and the pseudo namespace where macros live)

cgrand17:03:43

one stone, two birds

cgrand17:03:02

my recommandation is to wrap all defs (that are not support defs for the macros) in m/usetime thus you are sure they won’t be evaluated in the wrong existence plane 🙂

fbielejec17:03:53

Hi, I'm having issues when using :require on a namespace which needs to be a string (due to special character):

Assert failed: cljs.analyzer/foreign-dep? expected symbol got "@0xproject/connect"
(symbol? dep)
Repository that reproduces the problem (reproduce for example with lein figwheel dev): https://github.com/district0x/cljs-0x-connect

jrychter17:03:12

I suspected there was a MacOS performance tax: my builds under MacOS always seemed "slow". So I checked: installed a hackintosh system on my Linux machine. Building a sizable clj+cljs project: 90s (Linux) vs 125s (MacOS). Same hardware. That's a 30% difference! More that I'd expect. Thought this might be of interest to some of you.

tbaldridge17:03:11

same hardware though?

tbaldridge17:03:48

in my experience mac hardware was much more powerful than any linux hardware I had so the "perf tax" wasn't really a thing. MBPs have PCIe SSDs these days, last I checked that's still pretty rare in non-mac machines.

tbaldridge17:03:22

That also applies to hackintosh systems, realize you're running benchmarks on hardware the OS wasn't designed to work with.

jrychter17:03:28

Exact same hardware. Yes, I know there are caveats, but still, it's the best you can do to compare, short of installing Linux on a Mac (worth trying, too). This isn't entirely #off-topic — I'm pretty sure I'm not the only one for whom compile/build times are becoming a problem…

tbaldridge17:03:58

my point is that the times I've run Linux on a mac I've been completely disappointed in how badly it runs. I find it really hard to believe that anyone could get a 30% perf improvements in compile times simply by switching OSes

tbaldridge18:03:07

I suppose it's possible if the compiler is doing something really nasty with IO and the filesystem is optimized for something else.

dpsutton18:03:18

i gave my mac when i got 1.5 hours of battery on fedora. been enjoying my x1 carbon thinkpad

justinlee18:03:29

query about go blocks in core.async: when something goes wrong, the stack trace is often inscrutable. is there something i’m supposed to be doing to get better diagnostics or is this just something you have to deal with?

jrychter18:03:24

@tbaldridge Well, these are the numbers I get. But this isn't Linux on Mac hardware, it's Mac OS on a PC (a good one, with identical SSDs for both OSes). Frankly, I don't like developing on Linux because of the abysmal copy&paste and different keyboard shortcuts in every app. But — a 30% difference… This is very noticeable in ClojureScript work.

tbaldridge18:03:14

I'd submit that that's your problem. You're using unsupported hardware with OS X, hardware that probably isn't optimized. All macs have PCI-e SSDs these days, so they may have removed optimizations for SATA drives. In addition all macs are Intel processor based, so that can add another level.

tbaldridge18:03:28

So perhaps the wording needs to be "hackintosh tax"?

noisesmith18:03:10

@lee.justin.m this is an almost unavoidable aspect of async, unless somebody does bookkeeping about the flow of things you get lost, because stack traces don't reveal channel interaction (lazy sequences cause the same problem, to a lesser degree)

noisesmith18:03:32

@lee.justin.m something like core.async, or any other cooperative multitasking or channel based abstraction, is effectively replacing the stack with a more flexible custom structure (usually driven by some mechanism the underlying platform doesn't understand, like channel queues), so bad stack traces seem hard to avoid

noisesmith18:03:20

I wonder if there are good alternatives for stack traces, and what kind of design you would need to accomodate them

noisesmith18:03:24

message tracing?

justinlee18:03:20

@noisesmith i get that generally. it would be nice if there was a way to keep track of the top-level call, at least. just being able to see the top-most and bottom-most invocation would be great, but somehow the entire stack gets sheared off of my source code (sometimes)

noisesmith18:03:57

@lee.justin.m once you call go, the async channel driver is now the top of the stack

noisesmith18:03:04

(for all code inside that block)

noisesmith18:03:16

there's no stack relationship between code in that block and what launched it

justinlee18:03:41

i mean, if it just kept the parent stack, that’d be such an improvement

noisesmith18:03:51

but that's incoherent

jrychter18:03:00

@tbaldridge That's possible. I'm just trying to find a way to get a faster machine than my MacBook Pro 15" for Clojure+ClojureScript development. Benchmarks show that in single-core perf most latest Macs are slower than this machine.

justinlee18:03:44

well i don’t know. there’s this newer thing where you can see previous async events now in javascript

noisesmith18:03:23

I wonder how that works - I'd be afraid of fake stacks causing more trouble than they solve

justinlee18:03:11

maybe hard to implement, but it is a godsend. hell if the go macro could just pick up a file and line number and store it, that’d be enough. or if it had an option to manually register an identifier. but getting an error sheared from any context sure is a bummer 🙂

darwin18:03:03

@lee.justin.m you should be able to achieve something like this with latest Chrome Canary: https://box.binaryage.com/core-async-long-stack-traces.png

noisesmith18:03:10

oh, cljs core.async doesn't even give you line numbers in errors? that's worse than I thought

justinlee18:03:43

@noisesmith no it does, but the problem is that bottom of the stack isn’t in my code

noisesmith18:03:30

@lee.justin.m right, because a go block is rewritten to callbacks that get called by channels, it's all trampolined, it's not actually a stack

darwin18:03:50

but long chains of async calls produced by go-loop is still problem

noisesmith18:03:14

or, equivalently, the stack is only an implementation detail of the dispatch channels are doing

justinlee18:03:44

@darwin yea the async call stacks are great, but unfortunately not helpful here

justinlee18:03:31

okay well thanks for your help. i mostly wanted to make sure i wasn’t misunderstanding something. i’ll either have to deal with debugging difficulties or think about not using go blocks

noisesmith18:03:18

@lee.justin.m a pattern that's helped me with weirdly abstracted control flows is to have an atom (def debug (atom [])) and inside relevant code do (swap! debug conj {:where "here" :when (timestamp) :relevant {... ...}}) and then puzzle through the contents in a repl

noisesmith18:03:54

if you make it an optional callback you can even unit-test that things happen in some general order

justinlee18:03:44

that’s a cool trick in general. sad part here is that what i’m doing isn’t particularly complicated--i’m really just using go blocks to avoid callback hell. i’m thinking that maybe just using js native promises is easier. all i really want is to find which of my many go blocks caused the error without doing a bunch of prints. once i find it, it’ll be easy to figure out what the issue is.

noisesmith18:03:52

shouldn't the source line of the go block be unambiguous? maybe I'm misunderstanding

justinlee18:03:19

the bottom of the stack is in async.cljs, not where i initiated the go block

noisesmith18:03:48

the callback that async is calling should have been created inside your go block though, and that should be in there... somewhere

darwin18:03:10

@lee.justin.m just a wild idea, write your own go macro, which will emit go wrapped in a function which gets immediately invoked, this way I believe you get that function on your callstack, you can assign a name to anonymous function in a way which works in chrome devtools

noisesmith18:03:15

@darwin my understanding is that the go macro generates a series of callbacks, that are attached to the channels used in that block

noisesmith18:03:46

calling it inside something else shouldn't change the call stack when those cbs are invoked

noisesmith18:03:36

and if you want the stack trace to be useful (beyond showing the line of the file in which this go block callback was created), you'd need to generate fake stack data, because the go mechanism trampolines between channel callbacks, they don't invoke each other (you'd run out of stack for busy channels otherwise)

darwin18:03:23

@noisesmith I was assuming enabled async callstacks feature in devtools

noisesmith18:03:05

OK - I have no idea how that works

justinlee18:03:47

@darwin do you have any insight as to why the choice for nextTick was made instead of a promise-based implementation?

noisesmith18:03:19

@darwin so they must be instrumenting the promises to chain call stack information?

darwin18:03:07

sorry posted a wrong screenshot before, looking for correct one…

darwin18:03:39

@noisesmith yes, they are “remembering” parent call stacks on on async-call boundaries and reconstruct them in devtools stacktrace view: https://bugs.chromium.org/p/chromium/issues/detail?id=272416

darwin19:03:36

@lee.justin.m yes, nextTick has different timing characteristics than promises (micro-tasks vs. tasks)

justinlee19:03:01

oh right. i forgot about that nuance of the event loop

justinlee20:03:10

@darwin and @noisesmith if you are curious, it turns out I was hitting a known issue in cljs-http: https://github.com/r0man/cljs-http/issues/110. This behavior seems so obviously wrong to me I think I must not get it.

jmckitrick21:03:08

Is there a way to generate JS output for a Reagent project, say, and then serve the index.html via NodeJS and Express in that container?

dnolen22:03:05

pretty nice summary of what’s coming in the next ClojureScript release https://www.youtube.com/watch?v=WyISHu0JFpg

dnolen22:03:50

Please try 1.10.145, we’re collecting the last few issues to sort out before we cut a new version hopefully early next week

miikka12:03:01

Our app has problems again, this time with cljs.spec. Reported here: https://dev.clojure.org/jira/browse/CLJS-2641

lwhorton23:03:52

my goodness how is it I’ve never heard of https://github.com/swannodette/mori until right now? this is exactly what i’ve been looking for as an alternative to immutablejs for those horrid times I cannot use cljs