Fork me on GitHub
#clojurescript
<
2017-05-28
>
sophiago04:05:53

does anyone know whether figwheel compiles macros (on the first build, not autobuilds)? i would think so, but i'm getting that "wrong number of args" error that would point to no...

anmonteiro04:05:57

@sophiago the ClojureScript compiler loads your macros

sophiago04:05:19

i was pointing to the issue here about how they're compiled in a separate stage and that's why in self-hosted cljs it exposes form and env args: http://blog.fikesfarm.com/posts/2015-09-07-messing-with-macros-at-the-repl.html

sophiago04:05:37

(i rarely use macros, so this must be my first time using one in cljs)

sophiago04:05:23

@anmonteiro i guess you're saying i'd experience that behavior regardless of using figwheel's local server?

anmonteiro04:05:18

@sophiago hrm you need to clarify what you’re trying to do

anmonteiro04:05:32

macros in ClojureScript need to be written in Clojure and required with :require-macros

anmonteiro04:05:56

I’m guessing you’re not doing that and running into weird errors

sophiago04:05:12

yes, exactly. but i assumed that was only an issue of running the files locally and that the figwheel server would compile the macros, which must be incorrect

sophiago04:05:13

anyway, wouldn't it make sense to use cljc these days instead of :require-macros or would that not do it?

anmonteiro04:05:47

you can write the macros in a .cljc file. that is orthogonal to what I’m describing

anmonteiro04:05:22

because the compiler effectively runs in Clojure (on the JVM), your macros are expanded during analysis

anmonteiro04:05:34

that’s why they need to be written in Clojure

sophiago04:05:52

right, but you're saying with cljc i'd still need to use :require-macros?

anmonteiro04:05:48

the macros would be written in the :clj branch, so yes

sophiago04:05:13

i meant putting everything in a .cljc file

anmonteiro04:05:21

there’s absolutely no difference to the CLJS compiler if your macros are in a foo.cljc or foo.clj file

sophiago04:05:59

ah ok. i understand what you're saying now: they're still compiled to clj so i need to require them for the cljs compiler

sophiago04:05:45

@anmonteiro sorry, one more thing. isn't it possible to use refer-macros or :include-macros true on the same namespace? the github wiki shows how to do this for required namespaces, but not for the current one

anmonteiro04:05:57

yeah you can self-require

sophiago04:05:54

so like: (ns foo.core (:require [foo.core :refer :all :include-macros true]))?

anmonteiro04:05:21

(ns foo.core
  (:require-macros [foo.core :refer [macro-you-wanna-refer]]))

anmonteiro04:05:28

there’s no :refer :all in ClojureScript

sophiago04:05:45

ah so that was the problem (it's been a while)

sophiago04:05:31

hmm, i'm still getting a weird classpath error

sophiago04:05:39

figwheel is telling me Could not locate Foo/core__init.class or Foo/core.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.

anmonteiro05:05:49

@sophiago can you make a minimal repro I can look at?

anmonteiro05:05:56

should be fairly easy

sophiago05:05:14

let me see. the library is heavily intertwined 😕

anmonteiro05:05:36

something with just the requires should be enough

sophiago05:05:59

lol, well i created a whole figwheel project file with just the requires and an empty macro and still get the error

anmonteiro05:05:57

can you put it on GitHub or in a gist?

sophiago05:05:49

is that fine or do you need the whole project file to diagnose?

anmonteiro05:05:55

so is that a .cljc file?

sophiago05:05:05

nope. .cljs

anmonteiro05:05:22

your macro needs to be defined in Clojure…

anmonteiro05:05:33

you need to create a core.clj file where you define your macro

sophiago05:05:45

ah i should have figured that when self-requiring it needed to be .cljc

sophiago05:05:48

now i'm trying to call them from the aliased clj namespace and getting clojure.lang.PersistentList cannot be cast to clojure.lang.IFn. does that make any sense?

grumplet07:05:06

@tiensonqin I hit the error: [exp] goog.require could not find: figwheel.connect after a recent upgrade, so thought I'd pass on the solution. (I think we need to get a handle on exp/clojuresript upgrades somehow - they are not easy to do.) Anyway, if you hit this error, you need to change figwheel-bridge.js like so: https://github.com/WintonCentre/unspun/commit/a030d5596e9c046ae3329b3bf543aa0392a44e17#diff-a8aaf4a8ec45fa1d7054daff091c9365L228

danielstockton08:05:00

Can anyone give me some tips on debugging macros in cljs? A common technique is to put (println) statements everywhere, which obviously doesn't work when evaluating macros (not to the js console, anyway).

noisesmith08:05:09

sometimes what works is macroexpanding (probably in a clj repl), and then debugging the expanded code, finally converting back to fixed macro

danielstockton08:05:56

A little tricky because it is generating cljs code which can't be evaluated in a clj repl but should give me some more visibility at least.

noisesmith08:05:34

macroexpand doesn't care if the code it shows you is valid

noisesmith08:05:37

you can copy paste to cljs

rauh08:05:15

@danielstockton Connect to the NREPL before you start figwheel (manually).

rauh08:05:30

Then you can REPL just like you'd do in Clojure.

qqq08:05:55

What's the easiest way to embed a cljs interpreter inside a cljs app ?

mfikes12:05:37

qqq: Well, you can go down the road of adding self-hosting via cljs.js. There is some info at https://clojurescript.org/guides/self-hosting, but of course this is a pretty deep topic

qqq12:05:03

in cljs, what is the most efficient way of going from "a string representing a PNG" to "a core.matrix reprensetatino of the same iamge" ?

qqq12:05:45

is http://thi.ng/ndarray still maintined? why is it pulling in clojure 1.7

mfikes12:05:11

@danielstockton At a regular ClojureScript REPL, if your macro is defined in code on disk, you can use macroexpand, and if it doesn’t look right, change the code, and then (require-macros 'foo.core :reload) and expand again and/or try evaluating a form. If your macro is fairly self-contained (relies only on ClojureScript), you can fire up Lumo or Planck or any other self-hosted ClojureScript environment, and try different variations on the macro right in the REPL by abusing the $macros pseudo-namespace as described in http://blog.fikesfarm.com/posts/2015-09-07-messing-with-macros-at-the-repl.html

deg12:05:11

What is a good straightforward lein template for a ClojureScript utility project? (That is, ClojureScript code that will be used only as a dependency of other projects)

danielstockton12:05:29

@mfikes Thanks, I'll give that a look.

mfikes12:05:14

@deg I’d normally just do lein new mylib and simply add ClojureScript as a dep in project.clj and go from there. You’d probably want to also set up for unit testing your lib using some other community developed thing (like doo, or even Tach, if you are also targeting self-host)

mfikes12:05:08

I suppose adding :scope "provided" to the ClojureScript dep ^ makes sense

mfikes13:05:12

The main idea is that a ClojureScript lib is really just JAR dep with some ClojureScript source in it

deg13:05:57

Thanks! Meanwhile, the simplest one I found on Clojars was mies, which looks pretty close to that.

deg13:05:35

The curse of the vibrant ecosystem is that there are so many templates available, most of which are ancient or irrelevant.

deg13:05:05

Btw, I've never quite understood what :scope "provided" does.

mfikes13:05:33

@deg Let's say you want to make a ClojureScript library. For maximum usability, you want to make your library code only depend on some very old version of ClojureScript. So, in your project.clj you might have [org.clojure/clojurescript "1.7.28" :scope "provided"]. But, you don't want downstream clients of your library to accidentally have that old version transitively pulled in and placed on their classpath. Instead, you want the client to be able to specify any newer version of ClojureScript. The "provided" bit communicates that the consuming environment will provide that dependency. Ideally, the Maven system would choose the latest on its own, but the dependency resolution rules are not that straightforward. So, by using "provided" you work around that particular issue.

Pablo Fernandez13:05:47

Is there a way to have query params in cljs-ajax automatically url-encoded?

urbank15:05:13

How much do you tend to use reduce in you code to update state?

anmonteiro15:05:01

@danielstockton one thing that no one mentioned is the println technique you said you can't use

anmonteiro15:05:21

Turns out you actually can, but the output will be directed to your terminal instead

anmonteiro15:05:01

The trick is wrapping your println statements in binding [*out* *err*]

danielstockton15:05:35

It works at the clj repl but I think I need to play with my setup to see that when compiling the cljs. I'm running figwheel and it doesn't print to the cljs repl.

#?(:clj ~(binding [*out* *err*]
                     (println "test")))

anmonteiro15:05:46

It shouldn't print into the CLJS REPL

anmonteiro15:05:20

That'll print when the analyzer expands the forms

danielstockton16:05:02

Yeah, I didn't think it should. Just trying to work out where I can get it to print, except for evaluating it in the clj repl. If I evaluate it in the clj repl, I can see the expanded form anyway.

pedroteixeira16:05:35

trying to use the latest org.clojure/clojurescript "1.9.542" and [org.clojure/clojure "1.9.0-alpha17"] but getting error when compiling via figwheel

Failed to compile "resources/public/compiled/cards.js" in 5.656 seconds.
----  Could not Analyze  resources/public/compiled/cards/cljs/pprint.cljs  ----

  Invalid :refer, macro cljs.pprint/deftype does not exist 
is this familar to anyone, any tips? thanks

pedroteixeira16:05:01

hm.. this is not the latest, tried with cljs 1.9.562 but getting this same compilation error 😕

rauh16:05:17

Can you paste some code?

pedroteixeira16:05:23

just trying to start with empty project and latest deps.. lein project with cljsbuild :main to a cljs.user file

(ns cljs.user
  (:require
    [om.next :as om]))

(enable-console-print!) 
and trying (start-figwheel [:build :dev :cards]) from the repl

rauh16:05:56

Have you tried to clean the output dir? ie rm -rf ...?

pedroteixeira16:05:13

I removed :cljsbuild :compiler :preloads [devtools.preload] and got it to compile with lein cljsbuild but still fails via figwheel with Invalid :refer, macro cljs.pprint/deftype does not exist I notice that with lein cljsbuild I get some warnings:

Compiling "resources/public/compiled/cards.js" from ["src/clj/client" "dev/cards"]...
WARNING: Use of undeclared Var cljs.pprint/pprint at line 15 resources/public/compiled/cards/devcards/util/utils.cljs
WARNING: Use of undeclared Var cljs.pprint/with-pprint-dispatch at line 23 resources/public/compiled/cards/devcards/util/utils.cljs
WARNING: Use of undeclared Var cljs.pprint/code-dispatch at line 23 resources/public/compiled/cards/devcards/util/utils.cljs
WARNING: Wrong number of args (1) passed to UUID at line 564 resources/public/compiled/cards/cljs/reader.cljs
WARNING: Use of undeclared Var clojure.string/starts-with? at line 822 resources/public/compiled/cards/cljs/analyzer.cljc
WARNING: Use of undeclared Var clojure.string/ends-with? at line 972 resources/public/compiled/cards/cljs/analyzer.cljc
WARNING: Use of undeclared Var clojure.string/starts-with? at line 2643 resources/public/compiled/cards/cljs/analyzer.cljc 

pedroteixeira16:05:38

perpahs some mixed clj/cljs versions? will probably consider downgrading from these latest versions for now

lepistane18:05:35

thank you all for being such a wonderful community ❤️

hlolli22:05:09

@sophiago Is there a single quote instead of backtick in the macro bar?

sophiago22:05:08

no, but i do use a let statement outside of the quasiquoted part (a hack to evaluate gensyms)

sophiago22:05:41

that works fine in clj

hlolli22:05:47

Can you post that macro bar?

hlolli22:05:48

Looks maybe as if (macros/bar ..) macroexpands to ('() ...)

sophiago22:05:33

well, yes given the let. but that's never been an issue when in the same clj namespace

sophiago22:05:06

(defmacro square-limit [image n]
  (let [img (image)]
    `(do
       (corner-split (flip-horiz (below-top (beside-left ~img))) ~n)
       (corner-split (below-top (beside-right ~img)) ~n)
       (corner-split (flip-vert (flip-horiz (below-bottom (beside-left ~img)))) ~n)
       (corner-split (flip-vert (below-bottom (beside-right ~img))) ~n))))

sophiago22:05:53

^ the actual macro i'm using

sophiago22:05:53

oy, now i'm wondering if i need to qualify all those functional calls or if the expansion just occurs in the other ns and it's fine once required?

hlolli22:05:36

Maybe that (image) is the problem, you could move the backtick one level up and gensym the img.

sophiago22:05:26

sorry, i forgot earlier. usually i use that hack for gensym. in this case i'm just passing a function in userland

hlolli22:05:34

Yes (image) is just in the reader, isnt treated as function. So it isnt called. Youd need eval bit it doesnt exist in cls

sophiago22:05:52

but i don't see how that could be the problem when it expands fine when i don't need to require it to a cljs ns

sophiago22:05:52

unless it's not being expanded because the function calls are in the cljs namespace, which i haven't required to the clj one...etc. etc.?

sophiago22:05:32

do you know the answer to that last question? seems wise to rule out first

hlolli22:05:16

No, shouldnt matter. You can require .clj macros and use then in .cljs, ive only encounter problem with that using lumo, but then id need to clean the cash. Maybe recompiling would be needed in your case. So you should be able to rule that out.

hlolli22:05:43

Delete /out?

mfikes22:05:30

Is the first argument being passed to bar a form that looks like a list?

sophiago22:05:48

@mfikes it's a function literal

sophiago22:05:27

@hlolli i mean when your macros call functions from the cljs ns...whether you need to require that ns to your clj one and then qualify the function calls?

mfikes22:05:41

AFK, but it might be like ('(fn []))

sophiago22:05:26

@mfikes where are you going with this? it does seem to match the error message exactly...

hlolli22:05:57

I think it fits the message. Dont know what qualifying a function means.

mfikes22:05:16

Just mentally evaluating (image). Need to check at a computer :)

sophiago22:05:46

@mfikes thanks! testing my other hypothesis now

sophiago22:05:19

@hlolli as in (macros/bar ...) vs. (bar ...)

hlolli22:05:41

Try adding the backtick to front of let and give img# a hashtag at the end, i think it will work.

sophiago22:05:10

welp, my hypothesis about the function calls obviously made no sense since you cannot require a cljs ns into a cljs one!

adamvh22:05:23

what does (image) return?

sophiago22:05:34

a keyword stored in a global map

sophiago22:05:42

@hlolli to be clear, you're saying (let [img# (image)] ...)` will cause the call to image to be evaluated?

hlolli22:05:06

Yes, then the macro returns an expression that knows what to do with (image) otherwise its just in a reader, so that you could for example apply functions to the argumwnts of (image) before evaluation.

adamvh22:05:39

i think he's saying the call to image will not be evaluated at macroexpansion

adamvh22:05:52

and will instead be evaluated at runtime

adamvh22:05:39

as-written, your macro evaluates (image) at macroexpansion

sophiago22:05:48

oh...i think i'm starting to understand this

adamvh23:05:22

btw, you should call macroexpand-1 on your macro and see what you get

sophiago23:05:31

that hack with let works when it's in the same ns, but when requiring a macro from another you don't want anything actually evaluated at expansion

sophiago23:05:32

so in this case, i actually do need runtime evaluation for that call to make any sense. hence why it's being interpreted as a list

adamvh23:05:56

yea so image might be bound to nil

adamvh23:05:20

and you're trying to evaluate ('())

adamvh23:05:42

at macroexpansion

adamvh23:05:04

so it might make more sense for you to forego the let entirely and replace your ~img with (~image)

adamvh23:05:42

if what you want is to call image at runtime

sophiago23:05:48

well, the let still makes sense for efficiency, it just needs to be inside the quasiquote

adamvh23:05:18

true, and then you want img to be a gensym

sophiago23:05:30

no, not in this case

sophiago23:05:07

anyway, now i'm running into a problem where all the functions i'm calling in that macro are undeclared. i assume i need to unquote them?

sophiago23:05:50

(the same for the img var even though it's now inside the quasiquoted body fwiw)

adamvh23:05:39

symbols inside a syntax-quoted form are automatically prefixed with the namespace in which you're expanding the macro

adamvh23:05:06

so i think it's more likely that the functions actually haven't been declared

sophiago23:05:25

they haven't in the clj namespace. i asked that question several times above

adamvh23:05:36

sorry, i'm a latecomer

sophiago23:05:49

but if that's the issue i'm not sure how to resolve it considering you can't import a cljs ns into a clj one

sophiago23:05:19

i thought the answer before was that since nothing is being evaluated in the clj ns i'm fine

adamvh23:05:25

ugh this is more complicated than common lisp 😅

sophiago23:05:33

seems maybe i just need to qualify those function calls with the cljs ns?

mfikes23:05:00

I suspect you could write

(let [img ((eval image))] ...

sophiago23:05:49

@mfikes that would work as well. but now i'm on to another problem 😕

sophiago23:05:26

it's telling me all the function calls in the macro (which are from the cljs ns) are undeclared. i'm confused since that's the ns the macro is actually being evaluated in

sophiago23:05:14

@mfikes actually your way is the way i should have been doing it...not sure why appending gensym to the local var was suggested

mfikes23:05:21

@sophiago Is square-limit defined in a Clojure namespace with a name matching the one where the ClojureScript function corner-split is defined?

sophiago23:05:05

no, they're different

mfikes23:05:35

Syntax quote will end up qualifying the corner-split symbol with the namespace where the macro is defined.

sophiago23:05:57

ah! that's what i was asking all along

sophiago23:05:18

what's the way around that, seeing as i can't import the cljs ns to the clj one?

mfikes23:05:47

Just qualify the symbol with the ClojureScript namespace.

sophiago23:05:45

that should have been obvious 😛

sophiago23:05:04

but it's also telling me the local var img is invalid

sophiago23:05:45

wow, this is so verbose since i can't alias the cljs ns

sophiago23:05:31

but the local var img is still giving me trouble. i suppose i need to qualify that with the cljs ns as well?

mfikes23:05:01

Try macroexpand and see what you are getting

sophiago23:05:37

do you mean expand it without args? in that case i get "no such var." expanding it as i'm calling it just qualifies the function i'm passing

mfikes23:05:40

Just wondering if the result of macroexpand on the form results in valid ClojureScript.

sophiago23:05:44

on just the form it says it can't find it in its own ns... not sure why that is.

mfikes23:05:33

Oh, (macroexpand '(macros/bar ...)) where you replace ... with the arguments

mfikes23:05:49

That fails?

sophiago23:05:08

oh no, that just gave me back exactly how i called it except qualifying the function passed

mfikes23:05:50

Whatever that passed back will be evaluated as ClojureScript. Perhaps that's not what you want.

sophiago23:05:01

that just passed back the function call, i.e. (macros/square-limit (...) ...) except with the function qualified

mfikes23:05:44

Hmm. That sounds like it doesn't realize square-limit is a macro

sophiago23:05:55

ugh, i'm aware how much space i'm taking up in this channel (maybe fine since it's Sunday) but this is really baffling me