Fork me on GitHub
#clojurescript
<
2017-06-30
>
ingared05:06:32

I’m using react with rum, I manage components data in the state and been getting errors (on and off) mostly “No protocol method IDeref.-deref defined for type null:“. Atoms are behaving weird. I’m trying to use (@ — derefence operator for some of the local react components in methods declared with defn and rum/defc ). Let me know if I’m mis using @ operator.

ingared05:06:54

Sorry for spamming , I realized its a stupid mistake. I passed args in a weird fashion (instaed of passing [a [b]], passed them as [a b]). Not having type safety is expensive.

sundarj09:06:13

ingared: not sure if you're aware of this, but there is http://typedclojure.org/

dm305:06:33

@thheller - but why would the var be defined both in cljc/cljs if only one var definition will remain in the runtime. Is it to please the compiler for the macroexpansion stage?

stuartrexking07:06:55

I’m trying to understand what the #: means in #:nav.state here https://github.com/vikeri/re-navigate/blob/master/src/re_navigate/db.cljs#L21 I can’t find any reference to it in the spec docs. Can anyone point me in the right direction?

stuartrexking07:06:13

I’m asking here because I’m not sure if it’s a ClojureScript specific reader literal. I have no idea.

thheller07:06:58

@stuartrexking it is the the namespaced map reader syntax so you don’t need to repeat the namespace for every key

thheller07:06:04

it is applied automatically

stuartrexking07:06:49

@thheller Thank you. It’s clear now.

metametadata10:06:44

Is there any alternative to Slingshot for dealing with custom exception types in ClojureScript? I'm trying to make code less verbose, e.g.:

; "vanilla"
(try
 ,,,
 (catch :default e
   (if (foobar-exception? e)
     ,,,
     (throw e))))

; with Slingshot
(try+
 ,,,
 (catch [:type :foobar/exception] _
   ,,,))

dominicm10:06:27

If a clojure macro is spec'd, and I use it from cljs. Should compilation fail if I give that macro invalid forms (according to the spec)

rauh11:06:52

@metametadata CLJS will do an instanceof check if you catch a type: (catch FooBar ex ....)

thheller11:06:53

@rauh but CLJS doesn’t provide a “simple” way to create custom exception like FooBar 😉

rauh11:06:12

@thheller You you'd have to do a (deftype FooBar [x]) at the top level. IMO easier than possibly writing a library that can throw catch maps/vectors.

metametadata11:06:55

ideally such exception should be an instance of js/Error or, even better, ex-info

thheller11:06:58

but that doesn’t inherit from Error

thheller11:06:49

dunno exceptions don’t work too well in JS imho, especially with async code

thheller11:06:19

but I don’t know of any libraries that attempt to solve this

metametadata11:06:53

right, but unfortunately I do use them with core.async 🙂

metametadata11:06:51

actually there's a fork of Slingshot for CLJS and it kinda works but I'm still looking for alternatives if there're any

dominicm11:06:25

@thheller do I need to turn that on somehow? I'm not seeing that behaviour.

thheller11:06:16

not really? it should just work. as long as the macro and spec are properly loaded that is

thheller11:06:05

I re-used some of the clojure.core.specs.alpha for CLJS and they just work as is

dominicm11:06:38

@thheller I have a simple macro namespace with the spec defined in the same ns. I wonder if it's because of clojure 1.9-alpha14 vs cljs which is using the new .alpha ns... no idea

thheller11:06:07

yes, it requires alpha17

thheller11:06:34

it will look up clojure.core.alpha/macroexpand-check

dominicm11:06:12

I see all the instrument stuff is gone now. I haven't tracked spec, so I've probably got some catching up to do in that regards.

thheller11:06:47

its all still there .. just moved from clojure.spec to clojure.spec.alpha, same for all other namespaces, just append .alpha

mkvlr11:06:38

is there a way to use transit to encode clojure data and js data so it comes out with the same types on the other end?

pesterhazy12:06:27

@mkvlr what do you mean?

mkvlr12:06:30

@pesterhazy if I do a roundtrip encoding of e.g. {:hello [1 2 3] :world #js [1 2 3]} I get back {:hello [1 2 3] :world [1 2 3]}

mkvlr12:06:54

so I’m losing the information that the value under the world key was a js object in that case

pesterhazy12:06:32

that's a pretty exotic use case

mkvlr12:06:46

yeah, I bet

pesterhazy12:06:07

you can just pr-str as serialization method, that would work

pesterhazy12:06:23

that would be EDN-ish 🙂

pesterhazy12:06:59

but really I'd reconsider if what you're doing is necessary/makes sense on a deeper level

mkvlr12:06:03

we support cljs and js evaluation in a web worker and communicate via transit

mkvlr12:06:31

and would like to avoid having to call (clj->js) for things like plotly graphs

mkvlr12:06:08

maybe we should open a second channel that’s for json encoded data

pesterhazy12:06:20

you could manually JSON.stringify the values you know are going to be JS objects

pesterhazy12:06:43

as a serialization/deserialization filter

mkvlr12:06:27

could it work using custom reader writer as well?

mkvlr12:06:45

but I guess you’re right, string is probably fine for that use case

pesterhazy12:06:57

a tagged literal might be a good idea actually

#your.project/json "{\"foo\": 1234}"

mkvlr12:06:52

yes, but containing the string

mkvlr12:06:18

that should work nicely

tjtolton12:06:26

Are there any good clojurescript sound libraries? Like, there are a lot of great rendering libraries, like Impi, which is an ingeniusly lightweight wrapper around Pixi.js -- and now I want to figure out music and sound fx portion of the web game picture. This question is partly a gamedev question and partly a clojurescript question, so I'll ask in both places 🙂

manutter5113:06:01

Looks like chocolatier is using howler.js https://github.com/alexkehayias/chocolatier

dnolen14:06:37

a bugfix follow up to 1.9.660

wildermuthn14:06:23

I posted about this in #lein-figwheel, but hoping someone can give some advice about an issue between the latest versions of cljs and figwheel when running on node.js: https://github.com/bhauman/lein-figwheel/issues/525. I do a fair amount of CLJS work with Electron, which runs node.js, so maybe this is a small use-case. But I would love to get an idea if there are workarounds, or whether there’s already work started on it that I can help with.

wildermuthn14:06:08

Beyond reloading order, I found that reloading dependent namespaces also fails, basically making figwheel unusable (on the latest versions of itself and cljs) for node.js.

bhauman14:06:23

@wildermuthn this is definitely problem

bhauman14:06:19

I'm aware of it, unfortunately the fix requires a bigger change to figwheel

bhauman14:06:51

the interim solution is to use an older version of CLJS

bhauman14:06:00

not the best I know

bhauman14:06:23

Things moved out from under me on this one

wildermuthn14:06:24

Ok cool, thanks for the update. We’re delaying updating to the newer versions.

wildermuthn14:06:54

I was digging through the cljs commit history to understand the problem more. You happen to know where the change is?

bhauman14:06:10

commit history for CLJS?

bhauman14:06:40

it was back when there was a change in the way node dependencies were handled

bhauman14:06:35

I demonstrated this behavior to @anmonteiro at ClojureWest

wildermuthn14:06:55

Under Node.js don't need require entries in the goog.addDependency calls in cljs_deps.js?

bhauman14:06:25

what commit is that?

wildermuthn14:06:29

Out of my league on this one, but was curious to get a better understanding of how it works.

bhauman14:06:33

yeah that looks like the commit

bhauman14:06:57

I'm going to take a look at this today hopefully

dnolen14:06:47

@wildermuthn I think I removed that because I didn’t see how it was necessary - could have been wrong about that

dnolen14:06:05

a simple thing would be to revert that change and see if it solves the problem

dnolen14:06:13

@wildermuthn probably what you should do is try that locally, build ClojureScript and see if it fixes your issue

wildermuthn14:06:40

Ok great. Will do.

bhauman15:06:11

@dnolen yeah I was starting to check if that was necessary

dnolen15:06:37

I mean the fact that it breaks Figwheel is reason enough to revert if it’s harmless

bhauman15:06:38

sorry about depending on this stuff

bhauman15:06:55

I'm fairly sure its only informational and just supports runtime goog.require

dnolen15:06:11

yeah I don’t recall why I thought it would be a problem in my comment

dnolen15:06:17

@sundarj no we only use document.write during development

sundarj15:06:16

ah, that makes sense. good to know, thanks.

abarylko17:06:49

I need a small backend to serve my cljs app and do some proxying ... what would you recommend to do that?

spieden17:06:32

or lighttpd i suppose

abarylko17:06:48

I was hoping to use compojure and serve the JS from there while I implement my endpoint ...

abarylko17:06:05

sounds reasonable? Would you recommend other way?

abarylko17:06:03

also was hoping not to loose all the goodness of figwheel

dnolen17:06:24

@abarylko seems like a fine approach

bhauman18:06:03

@wildermuthn did you get a chance to revert that commit?

wildermuthn18:06:28

Didn’t get to. Been swamped with day-job. 🙂

wildermuthn18:06:43

Happy to leave you to it

bhauman18:06:00

please keep it on your list for now, I'll let you know if I get to it 🙂

wildermuthn18:06:22

Ok great. I’ll get it tested out then. Can report back in your issue queue if that works.

bhauman18:06:17

thanks! that would be great and pinging david as well of course ...

markbastian22:06:47

Hi folks, I am trying to write a particular macro and I can’t seem to get it to work in ClojureScript (I can get it working in Clojure). I was hoping someone here could help me out.

markbastian22:06:53

Here’s the macro:

markbastian22:06:05

(defmacro horner-expand [terms] (let [t# (rseq (eval terms))] `(fn [~‘t] (reduce (fn [b a] `(+ a (* b ‘t))) t#))))

markbastian22:06:35

To get it working in cljs, I have to define this function (as seen on several blogs):

markbastian22:06:37

(defn eval [exp] (:value (cljs/eval-str (cljs/empty-state) (str exp) “” {:eval cljs/js-eval} identity)))

markbastian22:06:41

In klipse, when I do this it works: (macroexpand ‘(poly.core/horner-expand [1 2 3])) or even (macroexpand ‘(poly.core/horner-expand (vec (take 3))))

markbastian22:06:01

the point being that I need the eval to put an expression in the argument.

markbastian22:06:15

My challenge is that I can’t seem to do this:

markbastian22:06:48

(def x [1 2 3 4]) then (macroexpand ‘(poly.core/horner-expand x))

darwin22:06:58

@markbastian cljs/eval-str is available only in bootstrapped clojurescript mode, you are aware of it, right?

markbastian22:06:43

Yes, I think I understand correctly. In fact, I can run my eval function just fine.

markbastian22:06:09

I am not sure if my problem lies in getting the eval or the symbol resolution working correctly.

markbastian22:06:51

I can inline (macroexpand '(poly.core/horner-expand [1 2 3])) and it works. The macro would not work with this form without the eval.

markbastian22:06:56

I just can’t seem to (def x [1 2 3]) then (macroexpand '(poly.core/horner-expand x))

darwin22:06:10

I don’t understand why you need cljs eval, [in cljs] macros are expanded at compile-time written in clojure and running in jvm

darwin22:06:20

or do you target bootstrapped cljs specifically?

darwin22:06:42

so you need your macros to be written in cljs to be executed on client side?

markbastian22:06:07

Yes, I want to execute the macro-generated code in a klipse page.

markbastian23:06:02

I apologize if I am not stating this correctly, and my understanding may be way off.

dnolen23:06:31

that’s going to be pretty tricky

dnolen23:06:03

I think you need to thread the environment into your eval

dnolen23:06:18

otherwise x won’t resolve

markbastian23:06:56

Thanks for the info.

markbastian23:06:06

Would I pass the environment in as the state argument to cljs.js/eval?

dnolen23:06:08

in Clojure the evaluation environment will be implicit since evaluation / compilation are really interleaved

mfikes23:06:08

It can be made to work. As David alludes to, your eval needs to be able to see the ambient environment.

cljs.user=> (ns poly.core$macros)
nil
poly.core$macros=> (require '[planck.core :refer [eval]])
nil
poly.core$macros=> (defmacro horner-expand [terms]
              #_=>   (let [t# (rseq (eval terms))]
              #_=>     `(fn [~'t]
              #_=>        ~(reduce (fn [b a] `(+ ~a (* ~b ~'t))) t#))))
#'poly.core$macros/horner-expand
poly.core$macros=> (def x [1 2 3 4])
#'poly.core$macros/x
poly.core$macros=> ((poly.core/horner-expand x) 7)
1534

mfikes23:06:41

The key bit is the (cljs/empty-state) can't be there.

mfikes23:06:50

Klipse probably has its state atom somewhere, perhaps you can access it.

mfikes23:06:22

They key is that state atom the place where the Var x will be known.

markbastian23:06:36

Ok, I was wondering about that. It was just the default that all the examples I was looking at were using.

mfikes23:06:10

There is probably something like klipse.core/st

mfikes23:06:47

Or, just def your own thing, like (def st (empty-state)) and use it for all your evaluation.

moxaj23:06:59

@markbastian I think in the case of klipse, you can use cljs.env/*compiler*

mfikes23:06:34

Yeah, that's true 🙂

mfikes23:06:55

cljs.env/*compiler* gets automatically bound, so

(identical? lumo.repl/st cljs.env/*compiler*)
and
(identical? planck.repl/st cljs.env/*compiler*)
are true. Same thing probably holds in Klipse.

markbastian23:06:11

The eval method does work with cljs.env/compiler, but it still won’t resolve the symbol.

mfikes23:06:50

Are you doing your (def x [1 2 3 4]) in Klipse (in self-hosted ClojureScript)?

markbastian23:06:17

`(defn eval [exp] (:value (cljs/eval-str cljs.env/compiler (str exp) “” {:eval cljs/js-eval} identity))) (defmacro horner-expand [terms] (let [t# (rseq (eval terms))] `(fn [~‘t] (reduce (fn [b a] `(+ a (* b ‘t))) t#)))) (def x [1 2 3 4]) ;(macroexpand ‘(poly.core/horner-expand x)) (macroexpand ‘(poly.core/horner-expand [1 2 3 4]))`

markbastian23:06:25

There’s the whole thing.

markbastian23:06:56

The last form (inline [1 2 3 4]) works ok.

markbastian23:06:47

when I swap it to resolve x I get #error {:message “Could not eval my.klipse”, :data {:tag :cljs/analysis-error}, :cause #error {:message “No protocol method IReversible.-rseq defined for type undefined: at line 1 “, :data {:file nil, :line 1, :column 1, :tag :cljs/analysis-error}, :cause #object[Error Error: No protocol method IReversible.-rseq defined for type undefined: ]}}

markbastian23:06:07

I am assuming x is undefined at this point.

mfikes23:06:27

Are you defining your macro and then trying to use it from the same namespace?

markbastian23:06:00

Oh, I am doing this:

markbastian23:06:05

(ns poly.core$macros
  (:require [cljs.js :as cljs]))

markbastian23:06:26

so I am in this ns

mfikes23:06:56

What do you see if you evaluate

(get-in @cljs.env/*compiler* [:cljs.analyzer/namespaces 'poly.core$macros :defs])

mfikes23:06:31

Hopfully you see a map with horner-expand and x as keys

markbastian23:06:23

{x
 {:name poly.core$macros/x,
  :file nil,
  :line 1,
  :column 1,
  :end-line 1,
  :end-column 7,
  :meta
  {:file "my.klipse", :line 1, :column 6, :end-line 1, :end-column 7},
  :tag cljs.core/IVector}...

markbastian23:06:35

let me find the horner-expand part as well

markbastian23:06:59

horner-expand
 {:protocol-inline nil,
  :meta
  {:file "my.klipse",
   :line 1,
   :column 11,
   :end-line 1,
   :end-column 24,
   :macro true,
   :arglists '([terms])},
  :name poly.core$macros/horner-expand,
  :variadic false,
  :file nil,
  :end-column 24,
  :method-params ([&form &env terms]),
  :protocol-impl nil,
  :arglists-meta (nil nil),
  :column 1,
  :line 1,
  :macro true,
  :end-line 1,
  :max-fixed-arity 3,
  :fn-var false,
  :arglists '([terms])}

dnolen23:06:27

@mfikes I think the issue is the eval happens in the macro ns? so lookup for x will happen there?

mfikes23:06:24

Yeah, it is probably cleaner to define the macro in a macros namespace and then consume it from a runtime namespace. I'm not familiar with the mechanics of Klipse.

markbastian23:06:36

ok, here’s my complete example:

markbastian23:06:46

klipse-cljs
(ns poly.core$macros
  (:require [cljs.js :as cljs]))

;Note that we need to define our own eval function so that we can evaluate our macro args. 
;See  for details.
(defn eval [exp]
  (:value (cljs/eval-str cljs.env/*compiler*
                  (str exp)
                  ""
                  {:eval cljs/js-eval}
                  identity)))

(defmacro horner-expand [terms]
  (let [t# (rseq (eval terms))]
    `(fn [~'t]
     ~(reduce (fn [b a] `(+ ~a (* ~b ~'t))) t#))))

;works
(macroexpand '(poly.core/horner-expand [1 2 3]))
;not yet
(def x [1 2 3 4])
(macroexpand '(poly.core/horner-expand x))

markbastian23:06:01

Just wanted to make sure I didn’t miss anything.

mfikes23:06:27

I'm able to repro your IReversible thing with the eval you defined.

mfikes23:06:22

Here is the full stack, in case you don't have access to it

No protocol method IReversible.-rseq defined for type undefined:
	cljs.core/missing-protocol (cljs/core.cljs:281:4)
	cljs.core/-rseq (cljs/core.cljs:643:1)
	cljs.core/rseq (cljs/core.cljs:3053:4)
	cljs.analyzer/macroexpand-1* (cljs/analyzer.cljs:5434:70)
	cljs.analyzer/macroexpand-1 (cljs/analyzer.cljs:5467:49)
	cljs.analyzer/analyze-form (cljs/analyzer.cljs:5693:63)
	cljs.analyzer/analyze* (cljs/analyzer.cljs:5734:37)
	cljs.analyzer/parse-invoke* (cljs/analyzer.cljs:5162:119)
	cljs.analyzer/parse-invoke (cljs/analyzer.cljs:5250:44)
	cljs.analyzer/analyze-seq* (cljs/analyzer.cljs:5483:34)
	cljs.analyzer/analyze-seq*-wrap (cljs/analyzer.cljs:5487:43)
	cljs.analyzer/analyze-form (cljs/analyzer.cljs:5693:63)
	cljs.analyzer/analyze* (cljs/analyzer.cljs:5734:37)
	cljs.js/eval-str* compile-loop (cljs/js.cljs:1915:4)
	cljs.js/eval-str* (cljs/js.cljs:926:7)

markbastian23:06:38

My family just arrived and I must break away from the Joy of Clojure and take them swimming. I’ll keep poking on this.

markbastian23:06:47

I really, really appreciate all of your help.

markbastian23:06:03

If I can get this working it’ll be an amazing blog post.

mfikes23:06:36

@markbastian FWIW, your code can be made to work if, you change your opts from {:eval cljs/js-eval} to add two more keys

{:eval cljs/js-eval :context :expr :ns 'poly.core$macros}

mfikes23:06:36

The :ns key lets it know which ns x is in.

markbastian23:06:51

Yes! That did it. Thanks so much, guys!