Fork me on GitHub
#beginners
<
2019-12-21
>
didibus00:12:07

Most Clojure REPLs do not by default clear existing state

noisesmith00:12:46

also GHCi is different from haskell itself, while the code driving clojure's repl eval is literally the same code that runs when running your app

seancorfield00:12:00

Getting an editor/IDE setup where you can eval code from a source or test file with just a hotkey into a connected REPL is a much nicer workflow than trying to type directly into a REPL -- but it does take a bit more effort to get it up and running and some practice to get into that new flow.

seancorfield00:12:29

Then you can get into the habit of starting a REPL once and leaving it running (for days or even weeks) and just interact with it via your editor. Make a small change, eval, see the results immediately, rinse & repeat. But it's a very different workflow to how the "REPL" works in most other languages -- it's a bit more like Smalltalk (or the Lisp systems of old).

seancorfield00:12:19

That way you can "run your application" inside the REPL and interact with it while it is running -- as opposed to "run" being some external operation.

didibus00:12:08

@alper I didn't mean to be harsh, but it does take a while to learn the tooling and the REPL driven workflow of Clojure. Most of your issues with it for the first few hundred hours are going to be due to your lack of understanding and practice, and most of them will disappear as you progress. Not saying everything is perfect, but definitly your current concerns are things you'll just outgrow (like a beginner piano player complaining their fingers can't reach far enough to play a given chord). Like Sean said, in a typical workflow, I use lein run a grand total of 0 times a day, I just never need it. And I am in my REPL constantly, only restarting it at most once a day, often less then that.

alper20:12:26

I’m reading a book (brave) where long running REPLs I believe are totally de-emphasized and most code is run using lein run. I’m setting up the stuff now and I get why a tutorial would try to ignore all of this (and be fairly successful with that approach if it weren’t for these kind of confusing edge cases). In your analogy, I’m not trying to play wild chords, just some basic scales.

alper20:12:31

But hundreds of hours?

didibus20:12:12

Ya, I wish I could say a few hours. But I'm thinking about how long it took me, and it was probably more in line with 100 hours

didibus20:12:06

That could be that the tools are rough around the edges, I mean, most tooling is maintained by one person on their free time. It could be there that things could be made more intuitive and better UX and all, which would reduce that time a lot.

alper20:12:17

I may not be around for a 100 hours. I’m learning and evaluating.

alper20:12:46

Yeah, I’m getting the niche language experience very heavily now that I’m trying FP.

didibus20:12:58

But also, part of it is building the knowledge of how the read/eval cycle works in Clojure and how evaluation is handled

didibus20:12:44

Ya, Clojure will always feel a bit like that. I tell people its that same feeling you get from using Linux

didibus20:12:10

Like, everything is nice and simple, but there's no one adding the polish that say OSX has

didibus20:12:55

And I think that's a reason why it isn't super beginner friendly, and why its mostly used by very senior devs

alper20:12:28

I am a very senior dev.

alper20:12:39

I also am very sensitive to developer experience.

didibus20:12:31

I meant senior like prior experience with Lisps and JVM

didibus20:12:46

Like if your an Emacs user for 30 years

alper20:12:56

I mean I’ve done a LISP tutorial at some point but this seems to be the only current one left?

didibus20:12:06

The Clojure tooling and repl would be super natural

alper20:12:09

And I got as far away as I could of the JVM after university.

didibus20:12:10

Ya. That for sure means there's more to learn

didibus20:12:19

I know people who tried Clojure years ago for a bit. Stopped. Tried it again a few years after. Stopped. And now trying it again the 3rd is when it finally start to click

didibus20:12:28

I think the best dev experience would be to use Cursive in IntelliJ

didibus20:12:10

You should try it. It is free for non commercial use I believe.

didibus20:12:39

And I do recommend getting familiar with the repl driven workflow as soon as possible

alper20:12:03

That’s nice. I try not to touch IntelliJ and write everything I do in Code.

didibus20:12:51

Ya, I'm not a fan of intellij either, too bloated. I use Emacs, but In wouldn't recommend that to someone starting out

didibus20:12:17

But it does have the most out of the box just works Clojure experience I believe and is unbeatable for java

alper20:12:20

I’m getting familiar with it, but it’s a bit hard to figure out what “REPL driven” means. The main difference is that I can set it up so that it cleanly reimports the file that I’m working on and does not leave all kinds of garbage there as well?

alper20:12:52

This seems to work well right now, just holy shortcuts…

didibus20:12:16

Well, so. Repl driven is that you basically start a blank Clojure program (with the libraries you expect to make use of setup on your classpath). And from that blank slate, you inject at runtime additional functionality to piece together a full program

didibus20:12:39

Now you have to understand that Clojure is not file based. So the source files arn't known to Clojure. They're just where you put code and save it to retrieve it later.

alper20:12:46

And what’s the source code file for then?

alper20:12:22

This sounds like really weird situation, weirder even than the entire GOPATH thing.

didibus20:12:02

yes, the weird thing is that in Clojure parsing and compilation is a runtime event

alper20:12:09

But what does “load current file” mean then?

didibus20:12:33

In your IDE, that means the editor will copy the code in the editor file and send it to the REPL

alper20:12:55

And that will hopefully overwrite any old garbage that was there with the same names?

didibus20:12:14

It will overwrite things with the same name yes

alper20:12:30

But don’t people program collaboratively and distribute code?

alper20:12:38

Like run programs?

didibus20:12:51

With one or two caveats due to the underlying JVM, but those are rare and you are probably not using things that have those quite yet

didibus20:12:19

What it won't do is unload what has already been sent to the REPL

didibus20:12:01

For example

alper20:12:13

And for that you would occasionally clear the REPL I guess?

didibus20:12:26

(def a 10)
(println a)
Now load into repl it will print 10. Now delete (def a 10) from your file and load it again, it will still print 10. Because the repl still has a, even though you deleted it from your file it does not get deleted from the REPL

didibus20:12:07

Yes. And I was told calva has a function for that should be called refresh

didibus20:12:39

Not sure of the shortcut

alper20:12:58

OK. But in short it comes down to that this is more of a lifestyle than a tool?

didibus20:12:03

But refresh will delete everything from the repl and load it a fresh

didibus20:12:48

Eh, I guess that's one way to put it. It is a different approach to programming entirely

alper20:12:23

I mean to be fully productive I’ll have to inhabit this stuff, go deep on a bunch more tools than I would like and memorize a bunch of shortcuts.

didibus20:12:42

Think of the difference between a classical music composer write music on sheets of paper. Where as a rock band would jam along and write down things after once what they have is good

didibus20:12:01

Yea, pretty much

didibus20:12:09

That's why it has a steep learning curve

alper20:12:29

But people use source files for projects and collaboration though?

alper20:12:40

But maybe I’ll just finish the book first.

alper20:12:48

And my day3 of the Advent of Code.

didibus20:12:09

And you either hate it or love it. I find it pure fun and a joy, and so I enjoy that way of programming a lot more. That's why I put in the effort to learn

alper20:12:26

I’m considering this because I find Haskell to be offputting.

didibus20:12:27

Ya, you use source files and git

didibus20:12:38

Its more the way it comes together is different

didibus20:12:30

Clojure has features to load code from a file, as convenience, because that's the most common way to do it

didibus20:12:46

But its more of a convention based approach

didibus20:12:24

For example, lein requires clojure.set for you automatically when launching the repl.

alper20:12:34

And I hate type systems in general. It looks like Clojure doesn’t really have one?

didibus20:12:58

Why? Because sometimes you just want to open the repl, mess around and not have to type a require for something so common

didibus20:12:36

But if you start the program without lein repl, that won't be there. That's what I mean by there's conventions around.

didibus20:12:34

It is a dynamic language, without a static type system. Though there is a a unofficial library called core.typed that adds optional typing, but it isn't very popular

didibus20:12:29

But it is still a compiled language. Unlike python, ruby and JS. That last part is a bit confusing, but for the most part you can ignore it as an implementation detail

didibus20:12:55

When you do lein run... What happens is a blank Clojure program is launched, your project.clj dependencies are added to the classpath, and your main namespace is loaded

alper20:12:52

I still haven’t read these parts of the book yet. I read half of it and thought I could with a bit of violence slam myself through the #adventofcode assignment.

didibus20:12:59

That means every top level form is read, compiled, loaded and evaled one by one from top to bottom in your main namespace

didibus20:12:32

But... As it encounters calls to 'require' it will pause and go load that namespace (the one defined by require) first. This happend recursively until everything is loaded in dependency (or required) order, where each namespace is evaluated from top to bottom

alper20:12:37

I think what’s nice about this is that it is off-putting enough to other programmers. My main is Python but that is so mainstream by now…

didibus20:12:59

And what you should understand is that's just a convention. You could write a different launcher and a require-weird function that loads things on a different order.

didibus20:12:24

And at the REPL, you choose the order by choosing what to send to repl and when to send it

didibus20:12:03

Ya, so.. For example, most Clojure devs find jupyter notebook a bit dumb

alper20:12:23

I don’t get it either.

didibus20:12:41

Because its just a more restrictive form of REPL. Where as Calva is like a more powerful jupyter notebook

didibus20:12:19

Where you get a full VSCode to edit the code and run it at the same time, and you can split the code accross multiple files, etc.

didibus20:12:16

Anyways. I recognize there's a lot to learn here.

didibus20:12:46

Thats another thing. Things in Clojure are well thought out. There's almost always a great reason why everything is as it is, even if it could be non obvious. But Clojure is super powerful!!

didibus20:12:02

Its the opposite of Python's one and only one way

alper20:12:24

Yeah, I hate that a bit especially in the tooling space.

didibus20:12:27

Clojure has all the features of all of the other languages combined (almost)

didibus20:12:13

Ya, it can be easy to lose yourself. At the same time, it means you can learn about and get exposed to a lot as well

didibus20:12:03

And the thing is, they're all pretty good. Like, people are always looking for what's the best X. Generally in Clojure all options are good, and just have different tradeoffs.

didibus20:12:22

For example, Boot, Lein, tools.deps are all good package manager!

didibus20:12:43

And people use each one successfully and happily

didibus21:12:16

But its not very beginner friendly. If someone asks which one to learn, its like... Any of them will be good enough

didibus21:12:13

Even for editors. Calva, Chlorine, Cursive, Cider, clojure-lsp, spiral, vim-fireplace, vim-iced, etc. They all have pros/cons

didibus21:12:14

Anyways 😛, I could go on and on... (I really like Clojure haha).

didibus21:12:35

I hope you end up enjoying it as well.

alper21:12:08

Haha. Let’s see how it goes.

alper21:12:20

It’s easier to get into than Haskell or Rust, that’s for sure.

didibus21:12:55

Ah! Well that's a start

alper21:12:58

And weirdly enough a bunch of people I know already seem to have made this jump.

ochuckles21:12:15

I'm also new to REPL development and I'm kind of confused. I'm in Cursive/IntelliJ and although it starts in my core namespace, the REPL doesn't automatically run my code by default. I have to copy-paste in all my def's and defn's into the REPL. Is that the intended workflow? Or is there some option I have to set?

didibus21:12:39

Well, I quite like Rust as well. My second favourite language after Clojure 😉

didibus21:12:25

@ That's not the intended workflow no

alper21:12:14

There should be a command that does the copy pasting for you?

didibus21:12:20

If you right click anywhere inside the file there should be a Closure Repl menu, and inside you should see Send to repl and Load file with the shortcut displayed

ochuckles21:12:29

oh i see it! thanks!

didibus21:12:01

Ya. So Load file in repl is the same as copy pasting the whole file to the repl

didibus21:12:24

And Sync files in REPL will load all out-of-date files from the editor to the REPL in the correct order

didibus21:12:58

I think based on the project setting, so starting from the specified main namespace

didibus21:12:47

And definitely learn to use: "Run form before cursor"

didibus21:12:01

Learn that shortcut and use it like every 30 seconds

didibus21:12:41

Normally I use Load file from repl and Run form before cursor the most

didibus21:12:59

And I almost never type in the repl itself

didibus21:12:44

When I change a function, add a function or add a def I do Load file from repl after

didibus21:12:57

Or if I changed many files I do Sync

didibus21:12:16

And then to test my code I write code to call my functions or test things directly in the file, sometimes prefixed with a #_ or inside a (comment) and run it with Run form before cursor

didibus21:12:20

I call that REPL only code, and that's why it is commented out. So it doesn't run on load, but the editors are smart enough to send the code inside the comment to the repl when doing Run form before cursor

ochuckles21:12:48

very cool. I see it can also run tests.

didibus21:12:25

Ya. Oh also using Switch repl ns is useful

didibus21:12:49

Because when you Run form before cursor, it runs it inside namespace the repl is currently in

didibus21:12:59

Not the namespace of the file you are in

didibus21:12:07

most often you'll want to switch the repl to the ns your are in before, so that shortcut is useful as well

sova06:12:07

any idea on how to make SMS / 2FA ?

didibus07:12:03

@sova I remember seeing this recently: https://github.com/suvash/one-time

hindol.adhya07:12:01

Stumbled upon this error: Can't embed object in code, maybe print-dup not defined. What does it mean? It goes away when I split reify into defrecord and instantiation.

hiredman08:12:44

It likely means you have a bad macro somewhere usually

hiredman08:12:02

Expanding into some weird object the compiler can't handle instead of into code that produces that object when run

ihor10:12:22

Hello How to disable this folding in Cursive?

andy.fingerhut17:12:24

I do not know the answer, but wanted to point out that there is a #cursive channel that might be more likely to find someone who knows.

dixelt10:12:18

Hi everyone! Had a small tool at work for querying different data-sources on staging environment and recently ported it to next-jdbc (https://github.com/dixel/loki). Since it's the very first time I tried to use next.jdbc, deps.edn and used macro, would really like to hear your feedback before getting any further with development. Also had a bit more specific question: is there an efficient way to feed IReducibleInc returned by next-jdbc into write-csv from clojure.data.csv? The latter works ok with lazy-sequences and previously I used java.jdbc and {:result-set-fn ...} which worked quite well even on large datasets returned by Presto engine in my case.

nick.romer14:12:32

Good morning! Is there an alternative for enfocus? There haven't been any commits in a while, and there has been an open issue for a long time. I am trying to follow the exercises in Living Clojure but get errors in the cheshire cat example that uses enfocus.

porkostomus15:12:45

Selmer is really nice for HTML templating

alper20:12:02

So in Calva do I have to have three windows open all the time? Code + REPL + Calva output?

alper20:12:22

(I got the more popular clojure integration before which seems to have been a mistake?)

alper20:12:18

Is there a way to make the Calva REPL word wrap? I couldn’t find a setting for this.

pez20:12:01

> So in Calva do I have to have three windows open all the time? Code + REPL + Calva output? I most often have only the editor open. Calva shows the result of your evaluation inline and also has a richer display of the results in the the hover of the evaluated text, from where you also can copy the results.

pez20:12:14

> Is there a way to make the Calva REPL word wrap? I couldn’t find a setting for this. There is no setting. I welcome a feature request about it. It makes sense that it would follow whatever setting you have in the editor, me thinks.

alper20:12:17

This is what I see now wrt to the wrap in the REPL. Things are getting cramped.

pez20:12:56

I would keep the REPL window closed and evaluate things inline in the editor instead.

alper20:12:36

Evaluate does not execute functions? I just ran it on my -main.

alper20:12:53

What is this saying to me other than that there is no syntax error in this def?

pez20:12:07

Yeah. Sorry. I’m assuming too much. What I do instead of evaluating in the REPL window, is that I put the things I want to evaluate inside a (comment…) form, often at the bottom of the file, but also often just below the the function I want to test. Calva has a command that evaluates the top level form inline, and the command treats comment forms as creating a new top level. You can see it in action here: https://calva.readthedocs.io/en/latest/try-first.html

pez20:12:31

I’m heading for bed. Please feel welcome to ask for help in #calva-dev. Hopefully others can step in while I catch up on lost sleep. 😃

alper20:12:57

No thank you! I fixed the bug in my code and can at a basic level work with this.

pez10:12:43

Glad you have progress! The offer still stands if you run into more questions.

alper13:12:47

Let’s say I’m overjoyed that I do not have to learn Emacs to get into this. 😅

davelearnsstuff20:12:27

I'm also trying to work through the Clojure for the Brave and True tutorial, but having a hard time getting the Emacs REPL even up and running. I get this error: "Symbol’s function definition is void: sesman-current-sessions" I found multiple answers to this on Stack Overflow and Reddit, but none of the answers work for me. I've tried this: https://github.com/flyingmachine/emacs-for-clojure/ but haven't gotten any results. I'm just getting back into coding after 15 years away, so it's 100% possible I'm making some really silly error here. But I'm following the tutorial word-for-word and failing. Any help would be massively appreciated. I'm thinking I should ditch Emacs for the time being and just use something simpler/more intuitive?

dpsutton21:12:21

if you want to keep up with emacs i can help you but it might be better to go with vs code and Calva

davelearnsstuff22:12:01

@ is that because of the learning curve? If so, I'll definitely opt for something simpler. Clojure Twitter recommended Cursive + IntelliJ.

dpsutton22:12:55

I think clojure community is largely 50% CIDER 50% cursive. You’ll be well served by cursive

davelearnsstuff23:12:48

thanks. much appreciated.

m373h4n20:12:49

is there "clojerl" related channel on this slack ?

alper21:12:44

Is there a beginner friendly way to profile a bit of code?

didibus21:12:59

The most beginner friendly is just to use time https://clojuredocs.org/clojure.core/time

didibus21:12:13

But its the most limited in features too

alper21:12:48

Tufte seems to require sprinkling (p) everywhere. I just want all calls from a call and their durations profiled.

didibus21:12:36

I actually have that one always in my REPL ready to go

alper22:12:50

Thanks, that paid off. I know where the time is going, but not why yet.

ericihli21:12:14

What would I search for to figure out how ClojureScript finds dependencies? I want to troubleshoot the behavior of a dependency. My plan was to clone the git repo and point my project to use the local version. Searching for things like "shadow-cljs classpath lookup" and '"clojurescript" dependency lookup' and I haven't found a link to a description.

ericihli21:12:01

Ah I think this is what I'm looking for. It's probably specific to the build tool (at least at the level I'm caring about). https://shadow-cljs.github.io/docs/UsersGuide.html#_dependencies So it just defers to NPM for looking up dependencies.

didibus21:12:12

Ya its specific to the build tool you use

welcome.to.dev.null23:12:30

Hello, I have a question regarding regex. I'm trying to convert a python program in which I'm using a regex with named capture group (eg. "(?P<Y>[a-z]).(?P=Y)" to capture things like "aXa" or "a0a" inside a string) but apparently there is no named capture group with Clojure/Java. I had a look at javadoc for regex that confirms it does not exists. Any idea how I can achieve this ?

andy.fingerhut23:12:09

You can use numbered capture groups with Java regexes. They don't have names. They are numbered by the order that their left parens appear in the regex, if I recall correctly.