Fork me on GitHub
#clojure
<
2019-01-16
>
Rahul Ballal03:01:47

Hi all! Extreme noob to Clojure here. Cider aside.. which dev environment is most suited for beginner Counterclockwise/ Cursive ? Any links on how to setup a dev environment ?

WhoNeedszZz23:01:54

I'd recommend Cursive. It's been the most complete environment for me and gets solid updates. Other environments I've been left in a broken state when the developer(s) of the tool get upset that something changed in core and they leave instead of fixing it. I can't deal with that instability.

lilactown05:01:23

I would suggest Cursive or VS Code + Calva

lilactown05:01:43

Counterclockwise hasn’t seen much love in the past years and so getting support for issues you run into might be difficult

✔️ 5
Alex Miller (Clojure team)05:01:52

CCW is no longer developed and I don’t think works on newer versions of Java/Clojure

kwladyka06:01:18

If you use emacs, use Cider. If Intellij use Cursive. If none, use Cursive, because Intellij is easier than emacs. You don’t want to learn hard editor + Clojure at the same time.

✔️ 5
kwladyka06:01:20

*harder editor doesn’t mean better. It is different depend on your preference.

👆 5
kwladyka06:01:25

I would love to see stable and extended Clojure plugin for Visual Studio Code. But today you can choose only between emacs + cider / Intellij = Cursive I guess.

kwladyka06:01:57

brew install leiningen clojure and you are ready to go 🙂

kwladyka06:01:40

clojure is clj command

seancorfield06:01:34

If you already use Atom, look at Chlorine or ProtoREPL. If you already use VS Code, use Calva. The main thing you want for learning Clojure is an integration between your editor and a REPL, so you can just hit a key combo and evaluate a form, a top-level form, or the entire file into that REPL — without typing into the REPL. All of those are sufficient.

WhoNeedszZz23:01:46

I don't know about Chlorine, but I know ProtoRepl doesn't really support ClojureScript. If the person is only writing Clojure then it works well.

seancorfield23:01:15

My understanding is that Chlorine is great if you're using shadow-cljs but not other ClojureScript build/dev tools. Since Chlorine is written in cljs and uses shadow-cljs and that's how it is developed (using itself).

WhoNeedszZz00:01:53

Well that's good to know. I use shadow-cljs myself, but the issue is if I need to use some other tool for whatever reason then now I have to change my entire development environment over a tool being switched out. That's disruptive.

seancorfield00:01:52

Go open an issue on the Chlorine repo then 🙂

seancorfield00:01:57

I'm pretty sure the maintainer is very open to supporting a broader set of cljs workflows. He seems very receptive and helpful in the #chlorine channel.

WhoNeedszZz00:01:41

That's great, but the reality is that it only supports one tool and thus creates this situation. I'm sure I'm not the first to address such a concern. If that changes in the future I'd be happy to check it out.

seancorfield06:01:15

(and if you use vim, look at fireplace? I’m not familiar with the vim/Clojure ecosystem, sorry)

👍 10
seancorfield06:01:06

For beginners, not having to struggle with the basics of an editor is a big help 🙂

👆 5
timrichardt14:01:00

A macro question:

(defmacro transact!
  ""
  [& body] 
  `(jdbc/with-db-transaction [conn# db]
     ~@(map (fn [transaction]
              `(jdbc/execute! conn# ~(honeysql/format transaction)))
            body)))

> (macroexpand-1 '(transact!
                                    (-> (insert-into :foo)
                                        (values [{:id (java.util.UUID/randomUUID)}]))))
=>
(clojure.java.jdbc/with-db-transaction
 [conn__27812__auto__ db-adapter.sqlite/db]
 (clojure.java.jdbc/execute!
  conn__27811__auto__
  (honeysql.core/format
   (->
    (insert-into :foo)
    (values [{:id (java.util.UUID/randomUUID)}])))))
The inner conn#, expanded, is a different one than the outer conn#. How to make the conn#s the same symbol?

enforser14:01:49

@timrichardt it has to do with the two layers of quoting

enforser14:01:22

try removing the quote on (jdbc/execute! ...)

enforser14:01:24

(defmacro foo
  [& body]
  `(let [conn# ~body]
     (prn conn#)))
;; conn# is the same 

(defmacro foo
  [& body]
  `(let [conn# ~body]
     `(prn conn#)))
;; conn# is different

timrichardt14:01:57

Yep, it is the layering but removing the quoting does not work in this case. Because the map is evaluated, it tries to evaluate conn# at compile time which is not possible.

eraserhd14:01:35

@timrichardt I would make the macro

(jdbc/with-db-transaction [conn# db] (doto conn# ~@(map (fn [transaction] `(jdbc/execute! ~(honeysql/format transaction))))))
<-- admittedly just avoids the problem

dpsutton14:01:16

can you use a let binding in the macro to capture conn# and then use that common binding in both quoted forms?

timrichardt14:01:09

@dpsutton Great, this seems to be the solution around this multi-layer-macro problem.

dpsutton14:01:23

i think ztellman solves this problem as well in ridley with a way to unify gensyms across quote boundaries like this

timrichardt14:01:24

@eraserhd Thanks, this works too, great.

dpsutton15:01:29

@timrichardt read this section of zach's Potemkin library: https://github.com/ztellman/potemkin#unify-gensyms (not advocating use necessarily. not advocating use but he for sure has thought of a great many problems)

👍 5
yuhan15:01:38

Is there any way to collect the statistics from a criterium benchmark? Trying to determine the time complexity of an algorithm by running it against different inptus

timrichardt15:01:52

@qythium not sure what you mean by statistics, but if you referring to the outputs of e.g. bench, run it against all your inputs inside with-out-str and transform/write the resulting string somewhere.

yuhan16:01:31

oh.. I suppose that's one way to do it

yuhan16:01:20

Strange to have to write a parser when surely those values are around as actual numbers somewhere? I tried searching through the documentation but couldn't find anything

timrichardt16:01:25

@qythium Yep, thats stupid 🙂 criterium.core/benchmark returns the result as data http://hugoduncan.org/criterium/0.4/api/criterium.core.html#var-benchmark

yuhan16:01:48

thanks, that's exactly what I needed!

yuhan16:01:45

(def timing-results
  (doall
   (for [n [5 10 15 20]]
     (criterium/quick-benchmark
      (fib n) nil))))

(map #(get-in % [:mean 0]) timing-results)
;; =>
;; (6.82956017409221E-7
;;  8.839126734896198E-6
;;  1.0012795602974459E-4
;;  0.0010987932789473685)

yuhan16:01:19

now to write a function which will look at that and estimate if it's O(n), O(n^2), O(n! log (n)) , etc.:thinking_face:

Lennart Buit16:01:22

That is probably more tricky than you would expect. I wouldn’t be surprised if there are mathematicians who spend their lives on that.

timrichardt16:01:30

Yep, especially since you will see things in the curve, that are due to the machine, not the ideal algorithm. E.g. jumps when certain chunk sizes are passed etc. Mathematicians usually don't care about such things.

yuhan17:01:22

Yeah, I don't need it to be very rigorous, just using this as a way of getting my head around the performance characteristics of core.logic programs - which seem really hard to reason about and blow up exponentially in unexpected ways.

yuhan17:01:13

I ended up just hacking together something in Python notebook which plots out the points and the regression lines for logn n, nlogn, n^2 , 2^n, then eyeball which curve fits best 😅

👑 5
idiomancy19:01:05

why would I be getting an error about manifest type when depending on a git source?

cider/piggieback                {:git/url ""
                                              :sha "fd99b9e3cfd2069a2484ba9e75dcd1bb04b78ed8"}
Error building classpath. Manifest type not detected when finding deps for cider/piggieback in coordinate {:git/url "", :sha "fd99b9e3cfd2069a2484ba9e75dcd1bb04b78ed8"}

dpsutton19:01:10

use 0ab53c69a12812b6eb4000862f12447b4874a949

dpsutton19:01:21

made a branch based on that change with a pom file added

idiomancy19:01:36

seems like we're not quite there yet, but at this point I'm creating extra work for you, so I'll just pull it down and see if it works with a local dependency

dpsutton19:01:20

try c4fbfdadb28a0d3c8700901677ab104d59ddbc27

dpsutton19:01:11

403142e5017628ce447aebf2e4c0c82d482488c3

dpsutton19:01:24

the pom had an issue with a dep on tools.nrepl

idiomancy19:01:14

{:git/url "https://github.com/dpsutton/piggieback.git" :sha "403142e5017628ce447aebf2e4c0c82d482488c3"} same error with that

dpsutton19:01:56

7bbe53ed38dfd79c3e9375d875d8c755a143a4b0

dpsutton19:01:02

this switches to deps.edn

idiomancy19:01:18

ill play with it for a bit and make sure nothing is weird

idiomancy19:01:24

yessss this is so great. feels so good to be able to do this again

Alex Miller (Clojure team)19:01:57

tools.deps is trying to determine the transitive dependencies for piggieback, but is not finding a manifest it understands (deps.edn or pom.xml)

Alex Miller (Clojure team)19:01:19

currently tools.deps doesn’t know how to read lein project.clj files

Alex Miller (Clojure team)19:01:29

one option is to forcibly declare it as a deps.edn project (it then treats a missing deps.edn as no transitive deps)

Alex Miller (Clojure team)19:01:21

you can do this by adding :deps/manifest :deps to your coordinate

dpsutton19:01:06

i can run lein pom and push that to the remote too, can't i?

Alex Miller (Clojure team)19:01:58

make sure you move your sha then

idiomancy19:01:58

gotcha, awesome, thanks!

Alex Miller (Clojure team)19:01:30

the generated pom just isn’t including your source files

Alex Miller (Clojure team)19:01:05

you could just use a deps.edn file like:

{:deps
 {org.clojure/clojure {:mvn/version "1.8.0"}
  org.clojure/clojurescript {:mvn/version "1.9.946"}
  nrepl {:mvn/version "0.4.5"}}}

Alex Miller (Clojure team)19:01:34

probably don’t even need nrepl there

Alex Miller (Clojure team)19:01:53

oh, maybe you do, not sure

dpsutton19:01:56

assumes src dir without explicitly putting that? I think it was lacking dirs from the lein generated pom due to profiles

idiomancy19:01:13

the nrepl is for working with intellij

Alex Miller (Clojure team)19:01:14

by default it uses src as the source directory

Alex Miller (Clojure team)19:01:27

but you could add :paths ["src"] to be explicit

dpsutton19:01:31

ok. that's what i thought. just making sure i didn't end up with the same problem

dpsutton19:01:29

thanks for the help @alexmiller

Graham Seyffert19:01:54

If I’m using doto, is there a clearer way to call doseq inside of it instead of wrapping an anonymous function in a function literal? If I want to use doto right now I have to do this -

(doto (Ctor.)
 (#(doseq [[a b] c]
     (.aMethod % a b))))

Graham Seyffert19:01:26

Leaning towards just doing this because I think it reads better -

(let [obj (Ctor.)]
  (do
    (doseq [[a b] c]
      (.aMethod obj a b))
    obj))

noisesmith19:01:31

let already has an implicit do in the body btw, so using do there is redundant

idiomancy19:01:47

ah, the old doodooseq

hiredman19:01:33

(reduce #(doto %1 (.aMethod (first %2) (second %2))) obj c)

hiredman19:01:32

that is assuming c isn't static, if c is a known value, I would write some code to generate the method calls and just paste them in

idiomancy19:01:19

(dorun (map (comp (partial apply .aMethod)
                       (juxt (constantly obj) first second))  c))

idiomancy19:01:29

lol, I have no idea what those values are

noisesmith19:01:00

as a small thing, you can replace (dorun (map ...)) with (run! ...)

idiomancy19:01:01

great tip! i didnt know that!

Graham Seyffert19:01:00

Feel like that’s going to generate reflection warnings?

Graham Seyffert19:01:39

Our project fails compilation if there are any reflection warnings, but I’ve never tried apply .someJavaMethod

noisesmith19:01:01

that simply doesn't work

Graham Seyffert19:01:28

Yeahh seemed dubious haha

idiomancy19:01:39

sorry! i diidnt test my solution at all 😂

Graham Seyffert19:01:40

Also people on my team would hate me for that

taylor19:01:19

apply relies on ☝️

noisesmith19:01:02

not only that, but .someJavaMethod isn't a thing we can put on the stack

👍 10
noisesmith19:01:26

. is an interop form, on compilation it generates code to (optionally reflect) and invoke a method

noisesmith19:01:41

it doesn't point to any real thing that you can use as an arg or put in a collection

Graham Seyffert19:01:17

Yeah that makes sense, and this isn’t even a static method

idiomancy20:01:54

alright everyone, I hate my idea too

noisesmith20:01:40

you can succinctly make a function that calls a method via memfn: (memfn someJavaMethod) - this is first class, can be used with apply or map etc.

macrobartfast20:01:40

when I load open the project I'm interactively developing in emacs/cider, I have to open all the clj files that contain functions I call in my main 'runner' file and eval them to avoid class not found errors... what am I doing wrong?

Graham Seyffert20:01:34

Oh interesting, didn’t know about memfn

dpsutton20:01:13

@macrobartfast did you load the main runner file? cider-load-buffer (C-c C-k) by default

dpsutton20:01:28

if it has a valid ns form with deps it should pull all of that in as normal

macrobartfast20:01:08

I did load the main runner file with C-c C-k without incident but still having to go load all the namespaces mentioned.

macrobartfast20:01:23

using lein repl, and cider-connect, if it matters.

noisesmith20:01:41

you need to require the namespaces that your runner accesses

dpsutton20:01:50

and are you in the namespace of the main runner?

noisesmith20:01:53

as long as you access the function from the main runner properly, there's no need to be in that ns

dpsutton20:01:00

i'm wondering if there is some confusion that those deps required by the main runner are "visible" in that namespace but not visible from the current ns. Its hard to tell if this is a bug or users error

noisesmith20:01:54

that should either error (if they can't be found) or guarantee they are loaded

macrobartfast20:01:23

I believe I did those things, but I'll do it all from scratch to double check everything; stand by (and thanks!).

idiomancy20:01:40

oh yeah +1 about memfn, thats neat!

idiomancy20:01:02

@noisesmith you've really made it worth my while to hang out here today!

👍 5
macrobartfast20:01:01

@dpsutton @noisesmith lesson learned, and never forgotten. I was missing the parent directory in src with the project name; my clj files were directly in src for some reason; everything evaluates now.

👍 5
jsabeaudry21:01:43

(map #(foo % baz) bars) vs (map foo bars (repeat baz))

dpsutton21:01:11

the former for me

👍 5
WhoNeedszZz23:01:41

PSA: Slack supports syntax highlighting for Clojure(Script) if you use the code snippet function over the code blocks. Makes your code easier to read here!

Graham Seyffert23:01:14

Not the same as GitHub’s

Graham Seyffert23:01:43

Oh you mean by clicking the “+” icon

Graham Seyffert23:01:48

Yeah but that’s a pain

WhoNeedszZz00:01:40

It's actually less work than typing out the backticks...and it's also a pain to read a bunch of lisp code with no syntax highlighting, especially when someone is asking for help on it.

Graham Seyffert23:01:10

At least for small things

WhoNeedszZz00:01:04

Naturally, for a single line of code that wouldn't be necessary.

Graham Seyffert23:01:31

Yeah I wanted it to work that way too @noisesmith