Fork me on GitHub
#beginners
<
2019-07-16
>
noisesmith00:07:32

#_ is comment-form

noisesmith00:07:46

it prevents an entire (balanced) form from being compiled

noisesmith00:07:55

user=> #_(anything goes here, clojure will not try to compile it)
42 ; to get a prompt
42

noisesmith00:07:17

it just skipped the whole list as if it hadn't been typed in

noisesmith00:07:25

didn't even think it needed to print a new prompt

noisesmith00:07:46

you can still get reader errors inside #_ though

noisesmith00:07:52

also, it stacks

noisesmith00:07:49

#_#_ is a useful idiom for commenting out a k/v pair in an inline hash-map

user=> {:a 0 #_#_ :b 1}
{:a 0}

👍 4
noisesmith00:07:25

I tend to use #_ quite a bit - I was just reminded today that I want to change cljfmt so it allows #_ on a line by itself (to comment out a definition without adding whitespace noise in git history)

noisesmith00:07:08

yeah - like that (also it's a handy thing for taking out a part of a function during debugging)

noisesmith00:07:00

that's useful too - but most people use (comment ...) in order to have a distinct block

noisesmith00:07:18

instead of a bunch of forms that each start with a #_

noisesmith00:07:14

also, if you define a series of zero-arg functions, you don't need to comment them out (though your editor might not make this as convenient, it's straightforward via a repl)

seancorfield00:07:12

It's just the default namespace created when a REPL starts up. It has some clojure.repl stuff referred in for convenience.

seancorfield00:07:11

That's Clojure doing that.

seancorfield00:07:39

No, just because the default Clojure REPL works that way.

seancorfield00:07:00

It creates a user namespace and runs those requires.

seancorfield00:07:57

I'm just talking about the default clojure.main behavior when you start a REPL.

seancorfield00:07:00

(! 666)-> clj -e "(ns foo.bar)" -r
foo.bar=> (->> (ns-refers *ns*) vals (map symbol) (filter #(not= "clojure.core" (namespace %))))
(clojure.repl/doc clojure.pprint/pprint clojure.java.javadoc/javadoc clojure.repl/find-doc clojure.repl/dir clojure.repl/pst clojure.pprint/pp clojure.repl/source clojure.repl/apropos)
foo.bar=> 
Here I tell Clojure to start a REPL and evaluate (ns foo.bar) first -- and then it runs those requires above, referring in those symbols.

seancorfield00:07:31

Leiningen uses the Reply library but it's also dealing with nREPL client/server stuff and all sorts of middleware etc etc. "It's complicated" pretty much by definition -- and if the behavior re user and the referred symbols is documented, it'll be somewhere in Leiningen's documentation I expect. Or Reply's docs. Or maybe nREPL's docs. I don't know -- I don't use any of that stuff.

seancorfield00:07:28

At work we switched from lein to boot back in 2015 and then we switched from boot to the Clojure CLI/`deps.edn` stuff last year.

dpsutton01:07:46

CIDER is an nrepl client through and through

seancorfield01:07:52

lein is the most commonly used tool in tutorials and books -- but I do think it's important for beginners to look at the "standard" Clojure CLI stuff.

seancorfield01:07:32

CIDER supports the Clojure CLI stuff (but it will still inject nREPL as a dependency to start a client/server REPL).

seancorfield01:07:07

I expect, over time, tutorials and books will probably shift over to the Clojure CLI for introducing people to Clojure. Editor tooling has been adding support for deps.edn over the last year or so.

andy.fingerhut01:07:16

I wouldn't say starting with Leiningen is a bad recommendation. It does have stuff under the hood that usually helps you, but if you want to understand all of the pieces, there are more parts under the hood.

seancorfield01:07:34

^ This, definitely. I was able to find the code for exactly what the Clojure REPL does pretty quickly, but I still haven't managed to chase down exactly where in the Leiningen/Reply/nREPL stack the "same" thing happens! Lots of magic involved 🙂

seancorfield01:07:13

Part of why I tend to steer beginners to clj and deps.edn is just because there's a lot less "magic" involved -- fewer dependencies, no unpleasant surprises caused by ~/.lein/profiles.clj containing plugins that you forgot you added, etc.

seancorfield01:07:49

(the number one cause of beginner problems with Leiningen tends to be something they added to that profiles.clj file because something they read somewhere suggested a plugin to "make life easier" but then it conflicts with some other project they're trying to work their way through)

andy.fingerhut01:07:17

And a relatively common root of Leiningen problems for experienced developers, too, but sometimes difficult to remember to rename ~/.lein/profiles.clj as a troubleshooting step if you haven't done so in a while.

seancorfield01:07:10

Heh, the only thing in my ~/.lein/profiles.clj file is

:socket {:jvm-opts ["-Dclojure.server.lein={:port 55555 :accept clojure.core.server/repl}"]}
so I can do lein with-profile +socket ... so I can then connect to whatever starts up via Chlorine/Atom so I can avoid nREPL 🙂

jumar07:07:26

you can also use lein with-profile base ...

seancorfield16:07:00

@U06BE1L6T I specifically need to add that profile (and I have to use + to add the socket profile to whatever lein command I'm running).

jumar16:07:25

I was referring to the "rename ~/.lein/profiles.clj" tip - using the base profile is an alternative to this I think

seancorfield16:07:43

Ah, good to know.

alexmiller01:07:42

I think nrepl actually works from that same var, iirc

seancorfield02:07:04

Wow... that's... a lot of custom stuff!

John Collins03:07:35

Hello, I'm working on my first clojure app. Mostly it's been great, but I'm running into an issue with my ring server hanging non-deterministicly while processing a request. The failure results in the entire JVM (jdk-11) locking up indefinitely, which I am only able to stop by sending a kill signal from another process. Thought I'd ask if anyone has ran into this? I'm wondering if it may be related to the fact that I am making JNI calls to opencv in the handler, although the issue doesn't arise in independent testing of the code path (not through the server).

andy.fingerhut03:07:01

I don't know of any examples of what might cause that off hand, but if you can get access to a terminal where the JVM process was started when this happens, typing Ctrl-\ will show information about all threads that might show if they are executing some blocking call.

andy.fingerhut03:07:35

Perhaps there is a way to do that remotely without terminal access, too. Not sure.

John Collins03:07:59

Thanks, so far I can't get the terminal process to respond to any key presses. I'll look into whether it can be done remotely

John Collins03:07:06

I'll take a look, thanks for the help!

jimi04:07:26

Hello, newbie here. How do you guys run your db migration? Currently I do it every time my application starts (I'm using component and ragtime). I'm trying to mimic micro-services for the sake of learning, so my application is split into a different github project. But unfortunately ragtime complains about the conflicting migration after the first project. Is this actually a bad approach to do migration (splitting it into a multiple projects)? Should I create another project which contains all the migration scripts that has a job to do just that?

Crispin04:07:41

Put all your migrations in your project repo, but run them out of band. That is, not a part of your main server runtime. Run them as part of your deployment process.

Crispin04:07:34

you upgrade 'prod' from v0.1.2 to v0.1.3... you run the migrations on 'prod' db as part of that step

Crispin04:07:45

you might even bundle them into the uberjar, but you probably want to launch them with a different entry point (run a separate command on the shell using the jar at deployment time)

Crispin04:07:50

also microservices... why do that to yourself. If you are beginning, just build a monolith.

jimi05:07:58

Thank you for the answers. Yes, I've read several github project and they differentiate between running the db migration process and the actual app. For example:

(defn -main 
  [& args]
  (if (= (first args) "migrate") 
    (run-migration!)
    (run-app!)))
And about the microservices thing, I would like to know any difficulties I'm dealing with while build it. If this is a monolith project, this wouldn't become an issue for me. So to clarify things, it's alright for a project to have it's own migration script right? I was just wondering if this is correct, since ragtime complains about it, I wonder if it's a ragtime limitation or the author enforcing a "good" workflow.

jimi05:07:47

After some reading, ragtime complains after the first migration because the second and so on migration would contain different migration scripts with no overlap, for example: first migration runs [01.foobar.up.sql, 02.foobar.up.sql] from the first project, the second one runs [01.barfoo.sql] and it conflicts since it can't find the [01.foobar.up.sql, 02.foobar.up.sql] in the folder.

seancorfield05:07:39

@UL449EM4K Look at Migratus. I think it overcomes the purely linear approach in Ragtime.

jimi05:07:46

@U04V70XH6 Thank you. I'll definitely look at it!

John Collins04:07:03

Mangaged to to get the JVM to dump threads. Does seem like some kind of deadlock, but hard to interpret.

hiredman04:07:05

No deadlock, the only thread doing anything is the middle of transit encoding some lazy seq

hiredman04:07:59

My guess is your query is returning a very large or infinite lazy seq

hiredman04:07:32

And the time it takes to materialize/encode it causes your http request to timeout

hiredman04:07:47

If it is infinite you should see the heap usage grow until you oom, or you'll get a stack overflow error

hiredman04:07:59

If it is just very large or slow to materialize if you make two http requests in parallel you should see two identical or close to stacktraces but no oom/stack overflow

John Collins04:07:08

Hm, thing is the same request will usually succeed more or less instantly. Only once every 10 requests or so will it hang. And I'm delaying the requests so there's no contention.

hiredman04:07:59

Are you caching the results of an expensive query?

John Collins05:07:08

Even stranger, it seems to happen at a random point of execusion

hiredman05:07:52

I doubt it is random

John Collins05:07:41

No, I'm logging the code path extensively and it's always running. Random relative to my preception, haha

hiredman05:07:59

If you are logging it extensively then you know where it stops

hiredman05:07:59

But my guess is you are logging function calls, but not logging as your lazy results are realized, so you are missing most of what is happening

hiredman05:07:48

When you say hang, have you tried increasing the timeout on the http clone you are using?

John Collins05:07:54

It'll vary from the very first line logged to the last. Anywhere in here:

clojure
(defn get-route-data [route-hash]
  (let [route (first (query (-> (h/select :*)
                                (h/from :routes)
                                (h/where [:= :route_hash route-hash])
                                (h/limit 1)
                                (hsql/format))))
        _ (info "route-hash:" (:routes/routeHash route))
        bdl (bundle/to-map (download-route-bundle route))
        _ (info "Downloaded route bundle.")
        msg (bdl "brainos.nav.static_map")
        tensor (.getData msg)
        tf (.getTransformation msg)
        tf-mat (utils/tensor->mat tf)
        static-map-mat (utils/tensor->mat tensor)
        _ (Imgproc/cvtColor static-map-mat static-map-mat Imgproc/COLOR_GRAY2BGR)
        _ (info "Colored")
        static-path-msg (bdl "brainos.nav.static_path")
        static-path-tensor (.getPathData static-path-msg)
        static-path-data (.asByteBuffer (.getData static-path-tensor))
        static-path-mat (utils/tensor->mat static-path-tensor)
        ^MatOfPoint path-indices (utils/to-img-indices static-path-mat tf-mat)
        _ (info "Creating path indices array.")
        path-indices-array (.toArray path-indices)
        _ (info "Creating path-points.")
        path-points (loop [idx 0 ret (transient [])]
                      (if (= idx (count path-indices-array))
                        (persistent! ret)
                        (let [^Point p (aget path-indices-array idx)]
                          (recur (inc idx) (conj! ret (vector (.-x p) (.-y p)))))))
        img-buf (MatOfByte.)
        _ (info "IM encoding")
        _ (Imgcodecs/imencode ".png" static-map-mat img-buf)
        img-bytes (.toArray img-buf)
        _ (info "Writing img str.")
        img-str (.encodeToString (Base64/getEncoder) img-bytes)
        _ (info "Creating static-path")
        static-path (vec path-points)
        _ (info "Creating static map")
        static-map-transform (vec (utils/tensor->array tf))]
    (info "Return Route Bundle.")
    #:routeBundles
    {:height (.rows static-map-mat)
     :width (.cols static-map-mat)
     :staticMapImage img-str
     :staticPath static-path
     :staticMapTransform static-map-transform}))

hiredman05:07:04

Sorry, on my phone and th slack client is rending things as just a big empty space

John Collins05:07:18

Sadly slack doesn't seem to understand clojure code.

hiredman05:07:26

Ah, slacks dark mode is just broken on Android, wonderful

hiredman05:07:38

So you have work happening after your last logging, because you are constructing lazy seqs and not forcing them

John Collins05:07:52

vec will eagerly construct a vector right?

John Collins05:07:07

Hm, I specifically tried to get rid of lazy seqs with that weird loop, but haven't had luck.

hiredman05:07:47

The stacktrace you pasted is from a function named query

John Collins05:07:20

Yeah I'm currently doing a dirty recursive call to query

hiredman05:07:37

Which that function is calling

John Collins05:07:16

There's no stackoverflow situation here, but I should go ahead and fix that

hiredman05:07:49

I didn't say stackoverflow

hiredman05:07:09

The thread dumps, the stacktrace of the only thread doing anything in there

hiredman05:07:18

It is executing the query function, and in the middle of that somewhere transit encoding some thing

John Collins05:07:00

You might be onto something there

John Collins05:07:19

I did try switching between transit and prn-str and it didn't change anything. prn-str actually had some other, serisouly nutty bugs.

hiredman05:07:22

The bug isn't in transit or prn-str

hiredman05:07:53

It is some issue with the lazy seq you are constructing in query

John Collins05:07:06

So that stack trace was from before I removed this lazy seq: (map #(vector (.-x %) (.-y %)) (seq (.toArray path-indices))) and replaced it with the loop.

jumar07:07:14

@collins you said "the entire JVM (jdk-11) locking up indefinitely" - how does this manifest? Is really the whole process "frozen"? Or is it just your request thread?

John Collins08:07:08

The entire vm. Only way I can kill the process is with kill -9 <pid> form a different terminal. Been trying different opencv versions, including building from source. If I remove the opencv calls it works, but with opencv calls present the process will hang at seemingly a random point. Anyway, I'm done for tonight, thanks for all the help.

Crispin09:07:23

when its frozen, check the processes state, with ps or top. Is the state of the process D?

jumar09:07:52

Processes in uninterruptible sleep don't usually respond even to kill -9

PB13:07:51

Hey all. I tried to build an uberjar with deps.edn and it kept packaging until I ran out of space (a 200+gb jar). I used the following library and followed the instructions here (https://github.com/tonsky/uberdeps). Anyone know why this might have happened ?

souenzzo21:07:09

Hey please report this as a issue If possible, a minimal deps.edn to reproduce this behavior.

donaldball13:07:18

Did you include an apache commons library? troll

donaldball13:07:43

But srsly, does printing out your dependency tree uncover any pathologies?

ghadi13:07:07

Or writing a jar to a directory picked up by the jarring process

PB14:07:42

@donaldball not really. It is a similar set of dependencies that was working with lein!

PB14:07:47

@ghadi that would be rather funny

donaldball14:07:39

If the jar isn’t corrupt, you could unzip -l on it and see what hilarity it contains

PB14:07:02

I ran out of space so it's corrupt

ghadi14:07:04

@petr is the jar destination directory also on the classpath?

PB14:07:15

@ghadi no, target is not one of the paths

ghadi14:07:59

"Are you sure?" clojure -Spath | tr ':' '\n' | sort

PB14:07:48

Yeah, target it not one of the entries

ghadi14:07:05

ok -- I'd file a bug with uberdeps

PB15:07:25

Hmm weird. A restart and it seems to be working :S

credulous16:07:27

Hi, I posted this in #tools-deps but it’s probably more appropriate here.

credulous16:07:29

I’m a bit confused with my workflow using clj and deps.edn. Everything was so magic with lein, I never had to actually understand what was going on. 🙂 no such luxury/laziness here. I have an app that has both an API server and a clojurescript frontend. The server is using http-kit. In my deps.edn I have {:aliases {:run {:main-opts [ "-m" "alexandria.core" ] } } — in alexandria.core I initialize the db, start the http-kit server etc. In my global deps.edn, I have the alias :nrepl {:extra-deps {nrepl/nrepl {:mvn/version "0.6.0"}}} What I would like to do is start the server, and have an nrepl session start at the same time, preferably with both a repl prompt and a server to connect to from the editor (I use fireplace/vim) Right now I’m starting the server with clj -A:run, which doesn’t start a repl as near as I can tell and in a different terminal clj -R:nrepl -m nrepl.cmdline, which starts a nrepl server and in a different terminal just clj to get a repl prompt and in a different terminal shadow-cljs watch alexandria to get clojurescript compiling plus a clojurescript repl going I’m sure this is not the Right Way to do things.

andy.fingerhut16:07:54

Have you tried running clj -A:run:nrepl ? I have successfully used multiple aliases that way.

andy.fingerhut16:07:18

That should use both of the aliases, but I am ignorant of nrepl enough that I don't know whether it will start an nrepl server, too. It should add the dependency, but I don't know whether adding the dependency alone is enough.

ghadi16:07:24

it will not run two main functions

ghadi16:07:57

I would suggest having your own dev-time entrypoint namespace that called whatever you need to call

💯 4
ghadi16:07:07

start the service && start nrepl

ghadi16:07:27

or only start nrepl and start the service from your REPL

AM19:07:34

Anybody familiar with Sente and Reagent? I have the following issue:

AM19:07:06

I'm trying to give the users of a web app the ability to change their email

AM19:07:15

(Using neo4j db btw)

AM19:07:58

However, the page that submits that change is not working

AM19:07:10

You'll click submit, and nothing will happen

AM19:07:52

this is the relevant code

AM19:07:21

the button will disable, and will not re-enable, and the page just won't do anything

AM19:07:41

I think it's a front end issue as well because none of my debugs are triggering

AM19:07:57

Any help is much appreciated, I just cannot figure out what's going on with this code

noisesmith19:07:59

how are processing and change-email defined? I assume they get stuck in an unhelpful state

noisesmith19:07:58

also this isn't beginner friendly cljs code (I assume you are asking here because you are new on a project and someone else wrote this)

AM19:07:01

this is the let bindings for the function that generates the page

AM19:07:14

Exaclty!

AM19:07:21

I've been outed haha!

noisesmith19:07:51

I forget precisely how reaction works (haven't used cljs in over a year) but I'd look into the value of that change-email value as a starting place (and remember that "" is truthy, so it shows up as true in a test - perhaps (not-empty @change-email) would change things, or maybe not)

noisesmith19:07:13

or since that's only a test, and not using the value, just (seq @change-email)

noisesmith19:07:33

oh never mind it's already checking for empty

noisesmith19:07:12

but if you have figwheel set up, check out the values of change-email and processing?, or otherwise set them up to be logged, I think that will be informative

AM19:07:08

Sound good, Ill let u know how it goes

Renan Oliveira19:07:08

Hi guys, Do you knows books about stuart component ?

alexmiller19:07:05

It's covered a little in Clojure Applied

AM19:07:20

Oh hey its me hehe ^^

Eric Ervin21:07:35

ya. I almost suggested an id change earlier.

AM19:07:55

ANother question: is there an easy way to check the values of a web app

AM19:07:59

in the terminal

noisesmith20:07:59

figwheel makes this straightforward - one trick is attaching add-watch to an atom / reaction to print when it changes

noisesmith20:07:07

(that trick doesn't require figwheel)

AM20:07:40

:thumbsup:

credulous20:07:30

I cannot seem to get my work environment going. I’m not sure what I’m doing wrong or even what channel to ask about it. I’m using fireplace to connect to cider-nrepl through vim, with a clj based project. Weird things have started happening. I’ve tried a bunch of things but the state right now is that I start the repl server with

clj -Sdeps '{:deps {cider/cider-nrepl {:mvn/version "0.21.1"} }}' -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"
as instructed on the cider-nrepl site. I connect with vim using :Connect. The first time I try to connect, I get an error: Vim(return):E15: Invalid Expression:. The second time I try, it seems to work. After I connect, I try to evaluate a simple expression - (+ 1 2). The terminal with the nrepl server prints a stack trace:

credulous20:07:34

nREPL server started on port 52195 on host localhost - 
Exception in thread "nRepl-session-588832b7-43c8-4260-8324-0a14383dac6c" java.net.SocketException: Socket closed
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:116)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
	at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
	at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
	at nrepl.transport$bencode$fn__427.invoke(transport.clj:116)
	at nrepl.transport.FnTransport.send(transport.clj:41)
	at nrepl.middleware.print$send_nonstreamed.invokeStatic(print.clj:159)
	at nrepl.middleware.print$send_nonstreamed.invoke(print.clj:138)
	at nrepl.middleware.print$printing_transport$reify__818.send(print.clj:174)
	at cider.nrepl.middleware.track_state$make_transport$reify__3988.send(track_state.clj:214)
	at nrepl.middleware.caught$caught_transport$reify__853.send(caught.clj:58)
	at nrepl.middleware.interruptible_eval$evaluate$fn__909.invoke(interruptible_eval.clj:123)
	at clojure.main$repl$fn__9095.invoke(main.clj:460)
	at clojure.main$repl.invokeStatic(main.clj:458)
	at clojure.main$repl.doInvoke(main.clj:368)
	at clojure.lang.RestFn.invoke(RestFn.java:1523)
	at nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:79)
	at nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:55)
	at nrepl.middleware.interruptible_eval$interruptible_eval$fn__916$fn__920.invoke(interruptible_eval.clj:142)
	at clojure.lang.AFn.run(AFn.java:22)
	at nrepl.middleware.session$session_exec$main_loop__1017$fn__1021.invoke(session.clj:171)
	at nrepl.middleware.session$session_exec$main_loop__1017.invoke(session.clj:170)
	at clojure.lang.AFn.run(AFn.java:22)
	at java.lang.Thread.run(Thread.java:745)

credulous20:07:56

After that though, I can evaluate the simple expression just fine, and the result prints in the editor.

credulous20:07:11

It feels like I spend 3 days struggling with tooling for every 1 day writing code. 😞

noisesmith20:07:52

there's a vim plugin that uses a socket repl instead of cider (it has less features but is more likely to just work)

noisesmith20:07:30

also, I'm not sure if fireplace is up to date to use the newest cider changes

credulous20:07:44

ok, so maybe I’ll drop to a previous version of cider and try that.

seancorfield20:07:06

@noisesmith Are you thinking of https://github.com/Olical/conjure that works with neovim?

credulous21:07:31

I needed to update fireplace, I probably updated the version of cider-nrepl without thinking about it.

credulous21:07:03

Maybe tomorrow will be my coding day! 😄