Fork me on GitHub
#beginners
<
2020-07-28
>
coding.aaronp01:07:54

Is it possible to get a repl while also running -main? For example I can do clj -m app.core and it starts my ring server, but no repl. If I only say clj then I get a repl but no server. Possibly related, how would I set up hot code reloading? Or even manually reload?

seancorfield02:07:38

@coding.aaronp There are several options available to you. You can start a plain Socket REPL in any Clojure process by specifying a JVM option. You can connect to that via telnet or equivalent and some editors can connect to Socket REPL (most require nREPL, unfortunately).

seancorfield02:07:21

You can programmatically start any type of REPL inside your -main function, including nREPL but you'll need the nREPL library as a dependency of your main program for that.

seancorfield02:07:20

You could also start a REPL and then start the -main function from inside your REPL -- for most -main functions that will likely block you from interacting with the REPL (unless you start it asynchronously).

seancorfield02:07:59

It's common practice to write your -main in such a way that it simply calls a few other functions, and provides a way to start those functions easily from the REPL instead.

seancorfield02:07:00

See for example this comment form showing how to start/stop the web server in the REPL, just above the -main function https://github.com/seancorfield/usermanager-example/blob/master/src/usermanager/main.clj#L212

seancorfield02:07:54

For what it's worth, at work we use the JVM option approach to start a Socket REPL in a lot of our processes -- even in production -- and then we can connect to those processes via telnet or our editor. We prefer that approach because it involves no extra code or dependencies in our production apps.

seancorfield02:07:23

Now, on "hot code reloading" -- I just evaluate code into the REPL on every change. It's just a key chord (`ctrl-; B` in my case to eval the top-level form around the cursor). I don't even have to save the file to do that. Edit, eval, edit, eval, edit, eval... The REPL is always up to date that way. No need for anything to "watch" files and reload them in the background.

seancorfield02:07:06

If you listen to talks and podcasts featuring Stu Halloway talking about his workflow, he also avoids anything like that -- he evals code into the REPL as he changes it. It's also what Eric Normand recommends in his (excellent) REPL-Driven Development source (on http://PurelyFunctional.tv).

coding.aaronp02:07:54

Hmm very good food for thought, thanks

seancorfield02:07:14

I always recommend trying to avoid "magic" in tooling and just learn an effective but simple workflow.

coding.aaronp02:07:19

I've been using vim. I know the clojure plugin supposedly does that, but I haven't looked at it yet

nate02:07:53

Check out the #vim channel for help

seancorfield02:07:17

Working with a REPL that is integrated into your editor is best. Never type directly into a REPL when you're actually developing code. It's okay to type directly into a REPL when you're just playing around, but working from your editor is the most productive way to work, once you've gotten used to it.

seancorfield02:07:18

@dchristianbell That's not really a good topic for this channel. Perhaps have the discussion in #off-topic ?

nate02:07:48

+100 to all that Sean said. The closer you get to evaluating code directly from your editor, the faster you will go.

seancorfield02:07:14

@nate Not sure why #vim didn't get highlighted as a link (made me wonder whether the channel had been archived)...

nate02:07:47

Yeah that was weird, maybe it's because I'm on iOS.

seancorfield02:07:16

Fussy phone app? 🙂

nate02:07:31

I guess it doesn't highlight unless you pick it out of the list that pops up.

seancorfield02:07:25

(ah, there we go)

nate02:07:00

If your editor/plugin of choice uses nrepl (like none of neovim/conjure), there's a bit of path fiddling done in dev to facilitate starting nrepl and a dev version of the app. Usually takes a bit to get set up, but then it's smooth like the socket repl.

coding.aaronp02:07:05

Ok so... what do people think about cursive? Needless bloat, or does it get you closer to that ideal you just described?

seancorfield02:07:30

I generally recommend people continue to use whatever editor they're already comfortable with

seancorfield02:07:37

(as long as it has a Clojure integration)

nate02:07:47

Yes! Agreed.

nate02:07:18

1. The editor you already use 2. The editor your best clojure friend uses. 3. Emacs or vim.

seancorfield02:07:50

"Beware the cult of Emacs" 🙂

seancorfield02:07:59

(or the cult of vim)

nate03:07:08

Hahaha. Both!

nate03:07:40

No one ever gets to step three.

coding.aaronp03:07:42

Haha yep. I've been loving neovim for ages, but always willing to expand my boundaries - if it's worth it

seancorfield03:07:48

I've used TextMate, Sublime, Atom, LightTable, Emacs...

seancorfield03:07:02

I gather Conjure is really good with neovim.

nate03:07:21

Conjure us the bees knees. Check out #conjure

nate03:07:31

(Hey, there it worked)

coding.aaronp03:07:25

Oooooh that looks interesting

seancorfield03:07:52

I really must give Neovim and Conjure a try. I occasionally do some vi/vim editing but I've never tried to do serious Clojure editing in it...

nate03:07:24

It was great to start, and then was rewritten to use fennel and is even better. Now it supports other lisps too.

seancorfield03:07:38

(don't get me wrong: I love Atom + Chlorine and I have a lot invested in that in terms of integration with Cognitect's REBL so I'm not about to switch -- but it doesn't hurt to learn additional editors 🙂 )

seancorfield03:07:18

I have a couple of videos up on YouTube showing how I work with Atom + Chlorine + REBL.

nate03:07:12

You've made me want to try out atom and chlorine with your videos. Also rebl.

nate03:07:18

One of these days...

seancorfield03:07:35

I plan to do more screencasts soon 🙂

stardiviner03:07:25

@seancorfield What's your youtube channel? I want to subscribe. 🙂

seancorfield03:07:59

@stardiviner I think this is the friendly name for it https://www.youtube.com/c/SeanCorfield_A/

seancorfield03:07:41

^ @chris358 LMK if that link works.

seancorfield04:07:36

@dinbhardwaj As much as Emacs is far and away the most widely used for (serious) Clojure development, I really wouldn't recommend anyone trying to learn Emacs while they are also trying to learn Clojure.

simon.shauming11:07:06

Totally agree. I am not a stranger to Emacs and Lisp syntax to begin with. When I was trying to learn Clojure, first I thought it would be easy to skim over Java, Lein, REPL, Emacs, and cider-mode, .., and so on, superficially, I was wrong. The experience was so frustrating that I stopped learning it a couple times. So today, I start again with clj tool, on the usual "Hello World!" file. Well, I have accomplished a small, but concrete, step without sense of vagueness and uncertainty. So I agree with your comment. Don't get a newbie to learn Clojure on Emacs or Lein.

seancorfield04:07:31

The usage of Emacs as a percentage is dropping each year I think as more people come into Clojure...

seancorfield04:07:11

(and I used Emacs on and off for twenty years, so I'm not coming from an anti-Emacs place 🙂 )

seancorfield04:07:19

Ten years ago, Emacs had 70%, and IntelliJ just 9%. vi had 18% and CIDER didn't exist.

seancorfield04:07:37

Five years ago, Emacs/CIDER had ~45%, IntelliJ/Cursive had grown to about 27%. Vi was about 12%. LightTable and Sublime were next.

camsbury704:07:28

nice way to make {:a {:one 1 :two 2} :b {:three 3 :four 4}} => {:a/one 1 :a/two 2 :b/three 3 :b/four 4} ?

camsbury704:07:52

apart from just writing it myself

seancorfield04:07:23

@ `(reduce-kv (fn [m k v] (reduce-kv (fn [m' k' v'] (assoc m' (keyword (name k) (name k')) v')) m coll)` I think (see below)

seancorfield04:07:35

But there's not going to be anything built-in.

camsbury704:07:46

okay thanks 🙂 didn't know if there was

seancorfield04:07:39

Let me edit that to actually work: (reduce-kv (fn [m k v] (reduce-kv (fn [m' k' v'] (assoc m' (keyword (name k) (name k')) v')) m v)) {} coll)

seancorfield04:07:31

user=> (def coll {:a {:one 1 :two  2} :b {:three 3 :four  4}})
#'user/coll
user=> (reduce-kv (fn [m k v] (reduce-kv (fn [m' k' v'] (assoc m' (keyword (name k) (name k')) v')) m v)) {} coll)
{:a/one 1, :a/two 2, :b/three 3, :b/four 4}
user=>
(I actually tested it the second time!)

seancorfield04:07:49

One thing to be aware of, that sort of transform leans into using namespace-qualification on keywords as a sort of structural semantics which I'd be very cautious of.

seancorfield04:07:21

Qualified keywords are intended to identify entities that are unique across your domain, rather than imply any sort of nesting.

camsbury705:07:54

yea using it for fuzzy searches on nested maps

camsbury705:07:18

figured that would be a useful preprocessing step

seancorfield05:07:21

And what about maps nested three or more levels deep? 🙂

camsbury705:07:44

yep need that

seancorfield05:07:10

If you combined them with . instead of trying to qualify them, you could handle arbitrarily-nested maps -- and then you wouldn't be "abusing" namespace qualification...

seancorfield05:07:56

(keyword (str (name k) "." (name k'))) would do that.

camsbury706:07:05

sounds good!

seancorfield04:07:10

VS Code / Calva is the fastest growing usage, up 10% from even last year!

chris35804:07:54

crazy prediction: in 10 years time the most common development environment for clojure will be browser based e.g. code-mirror + parinfer

seancorfield05:07:40

I wonder... We've been promised cloud-based development as the norm for years...

chris35806:07:16

i guess my thesis is there will be a lot more people writing clojure, and a significant fraction of them will do so in the browser, because the browser will become the OS for many futurepeople. 10 years is probably optimistic. 😁

seancorfield06:07:33

I wish I could argue against that but, given that several modern editors are basically "browsers" with the editor written in JS, I don't think I'd find my own arguments terribly convincing at this point...

chris35806:07:41

heheh yes electron has a lot to answer for!

chris35806:07:30

i actually mean the browser though. my 9 year old barely has a concept of the file system. nearly everything she does is in a browser tab. but yeah, definitely a wild prediction which has been made before and not come true!

seancorfield06:07:41

We have the Chromebook as an example of what a browser O/S might look like -- but it still seems fairly niche to me. Of course, I'm ancient and still cling to a lot of seriously old-school practices! I think a good dev env should be able to run without an Internet connection of any sort (which is increasingly hard these days).

chris35806:07:45

i don't think internet connection == browser based

chris35806:07:22

agree it's niche right now

seancorfield06:07:40

That's a fair distinction.

chris35806:07:48

i also cling to seriously old-school practices!

seancorfield06:07:03

When I find myself using CodeMirror in REBL and it has paredit etc, I do sort of have a reality check and try to reconcile "browser" with "good editor experience" 🙂

pez07:07:00

Theia does a good job in making browser based editing as good as on the desktop.

noisesmith13:07:03

> my 9 year old barely has a concept of the file system even in the '80s / '90s most computer users had a minimal grasp on the file system

dinbhardwaj05:07:01

@seancorfield where did you get the data that emacs user are decreasing? I don’t believe the worlds best editor looses the shine. how it can loose member when more than 5000 package exists to meet your all needs at one place. Other editor are no competition. Even slack is on emacs now… https://github.com/yuya373/emacs-slack … once in emacs, you never have to go outside to do anything. Mail reading, new reading, slack communicator and Org to do list … everything is there…. Everyone should be half Nerd/Hacker if he can’t be full one… And Emacs will help him out… Rest everything is individual choice as you had suggested.

seancorfield05:07:05

I remember, back in the '90s, seeing HP demo an editor environment for C++ that was essentially all cloud-based (we didn't use "cloud" back then)

seancorfield05:07:25

@dinbhardwaj I went back through the State of Clojure Survey results for the last ten years.

seancorfield05:07:01

So it's a fact, despite your "religious fervor" for Emacs 🙂

seancorfield05:07:58

(and we really discourage "editor wars" here -- just as we discourage "religion" and "politics" 👀 )

seancorfield05:07:11

@chris358 Have you used any browser-based development environments?

dpsutton05:07:30

Those developer surveys only show percentage of market share. Its not clear if emacs user count is decreasing or just more people are developing clojure and all user counts are increasing and more people are using all of the different editors. I'm hoping its a bigger pie 🙂

chris35805:07:42

@seancorfield i've built a couple of domain specific ones: https://slingcode.net and https://chr15m.github.io/speccy/ (the latter is for cljs editing)

chris35805:07:28

i'm planning to add eval'ed cljs support to slingcode but that is 100% vapourware at he moment

seancorfield06:07:29

@dpsutton The number of respondents has gone from about 500 in 2010 to 2,500 in 2020 so you could argue that Emacs' numbers have grown (from 350 to 1075 roughly) except that we all know the survey respondents represent just a proportion of the community -- and, most likely, the most avid and engaged Clojure fans. That VS Code has grown by 10% in just the last year as Emacs' "market share" has declined slightly is indicative of a major shift in the community, I think the main takeaway is that we have more choices today and that a large portion of the community favors "other editors" -- which is a good thing: choice is important, and being able to onboard new Clojure developers using their current favorite editor is important.

dpsutton06:07:51

totally agree with that.

nmashton06913:07:11

Agreed – I think the availability of #calva was a big reason my spark of curiosity about Clojure was able to explode as rapidly as it did (thanks @pez!).

joao.micena13:07:42

Hi folks! Is there a best practice on how to use symbols from the same namespace on functions? I mean, I’ve been writing stuff like:

(def thing 1)
(defn a-fn
  [x]
  (+ x thing))
But I have the feeling that this is wrong because of the “implicit” thing inside the function. Should I always pass it as an argument?

manutter5113:07:36

By “definition”, (def thing 1) defines what other languages would call a constant. As long as you use it that way, and don’t use any of the functions that would let you change thing to a different value, you’re probably ok.

coding.aaronp13:07:53

I'm also a beginner, but I would think it depends on the situation. What you have there is a closure. You can call a-fn from another module and it works fine. But if you want thing to be more dynamic, depending on the module calling it, then pass it as an arg

manutter5113:07:31

The main idea is that your a-fn is “pure” (i.e. “good”) if it always gives the same result when given the same arguments.

manutter5113:07:00

Sometimes I’ll build something like this:

(def numstrings
  {1 "one"
   2 "two"
   3 "three"
   ;...
   9 "nine"})

(defn as-string
  "convert a digit to a string"
  [n]
  (get numstrings n))
By putting numstrings in a separate def, I’m keeping my function simpler and easier to read, and the value of numstrings isn’t going to change at runtime, so this is all good.

noisesmith13:07:16

the key is that calling def thing again later in your code should never happen

noisesmith13:07:30

it might happen during development, of course, but not in application code

manutter5113:07:46

Right, plus what’s the other one, alter-var-root or something?

manutter5113:07:20

You can tell I never use it 🙂

qythium13:07:15

there are also dynamic vars which you can rebind temporarily using binding or with-bindings , but these have to be explicitly marked with the ^:dynamic metadata

coding.aaronp14:07:11

What would be the best way to structure/add cljs to a clj project? I'm using the cli, got a ring server setup under src/clj/app Should I have src/cljs/... or make a whole new project? Something else?

aviv14:07:43

hi, how would you remove backslash from a string, i have tried the following but no-success, (s/replace "<?xml version=\"1.0\"" #"\\" "") => "<?xml version=\"1.0\"" won't work also for "\\" OR \backslash Desired result: "<?xml version="1.0""

manutter5114:07:48

You may be running into a REPL gotcha there--your replace is probably working, but the REPL will put backslashes in front of embedded double-quotes

dpsutton14:07:13

"<?xml version="1.0"" is not a valid string

dpsutton14:07:41

or, its a string and then a double literal 1.0 and then an empty string

manutter5114:07:28

(str/replace "<?xml version=\"1.0\"" #"\\" "")
=> "<?xml version=\"1.0\""
(println (str/replace "<?xml version=\"1.0\"" #"\\" ""))
<?xml version="1.0"
=> nil

dpsutton14:07:10

(println "<?xml version=\"1.0\"")
<?xml version="1.0"
nil

dpsutton14:07:21

you aren't replacing anything

manutter5114:07:37

That too 🙂

dpsutton14:07:05

consider the string "bob \n marley". it does not contain a slash and an n. it contains a newline

dpsutton14:07:28

likewise, your string does not contain a slash and a quotation mark, it contains a quotation mark