dev-tooling

bozhidar 2023-12-23T08:15:37.728919Z

@ericdallo I've finished writing today an article I've started 9 months ago https://metaredux.com/posts/2023/12/23/cider-clojure-lsp-sitting-on-a-tree.html 😄 Let me know if you have some feedback about or if you think I've missed something interesting/important.

8
7
pez 2023-12-23T08:29:40.187399Z

Typo here? > the big feature of Lisp is interactive programming, so I can’t imagine anyone programming with a REPL.

😆 2
bozhidar 2023-12-23T08:30:09.236859Z

😄

pez 2023-12-23T08:39:43.228509Z

How much static service does CIDER provide? Zero? If so, there’s some other mode providing formatting and such, I guess?

bozhidar 2023-12-23T08:45:24.454069Z

CIDER directly provides zero, but refactor-nrepl and clj-refactor.el provide some. But I think the analyzer implementation in clojure-lsp is better.

bozhidar 2023-12-23T08:45:51.568529Z

Admittedly I haven't used clj-refactor.el either. 😄

pez 2023-12-23T09:42:08.587349Z

The analyzer in clojure-lsp is absolutely stellar.

ericdallo 2023-12-23T14:26:19.836589Z

Wow, amazing post @bozhidar! 👏 Really agreed with everything, and liked the way you tell that both tools are complementary to each other. Nowadays I really see people using both together at Nubank and the in the community and at least for me I can't live without both!

2
🙇‍♂️ 1
vemv 2023-12-23T15:08:17.108009Z

Perhaps the article suggests that both analyses are equivalent, but clojure-lsp lacks eval and macroexpand, so without one hinting how to interpret certain constructs, it can give a variety of inaccurate info Then again, it's something that could be improved by bridging both approaches. Eric already facilitated that in a series of refactorings. It's something that I've absolutely love to happen - but first comes first, namely ironing our own flaws - there's always stuff to do CIDER side 😄

1
bozhidar 2023-12-23T15:30:13.314789Z

> Perhaps the article suggests that both analyses are equivalent, but clojure-lsp lacks eval and macroexpand, so without one hinting how to interpret certain constructs, it can give a variety of inaccurate info I'm a bit confused by this remark. Which part of the article are you referring to?

ericdallo 2023-12-23T16:00:05.359229Z

For sure @vemv, last year I added the first feature that uses runtime data in clojure-lsp, the stub features, which under the hood spawns a repl to get data for libs that don't have source like datomic, I moved all this logic to a lib called https://github.com/clj-easy/stub

💪 1
vemv 2023-12-23T22:53:18.176099Z

> I'm a bit confused by this remark. Which part of the article are you referring to? It's simply the absent high-level description of how clojure-lsp works (chiefly with a clj-kondo analysis) which has the mentioned drawbacks. Without mentioning those, a casual reader might as well imagine that these two approaches are equivalent. Tbh, one could compare both all day, perhaps to the point where one would confuse readers 😄

bozhidar 2023-12-24T06:23:56.017629Z

Well, I just assumed that most Clojure devs would be aware what’s possible with static analysis vs what requires a REPL and some code evaluation. But I do get your point.

mauricio.szabo 2023-12-26T00:15:16.161199Z

@borkdude REPL support in shadow is absolutely amazing. It's a solved problem for me, especially because Chlorine connects to the special REPL that shadow uses for evaluating stuff - I even (ab)use tap> to dinamically get the result of promises when they are resolved too

borkdude 2023-12-26T07:11:46.230449Z

Ok, I think the answer should not be: use only static analysis. To emphasize it again: I’ve always intended clj-kondo to be a tool in ADDITION to the REPL to be even MORE productive. Please get people off the path of either/or. Again, Cursive users are never faced with this false dilemma, CIdER 🍺 users shouldn’t have to be either. Merry Christmas 🎄

👍 1
bozhidar 2023-12-26T09:49:12.996929Z

@borkdude I’ve tweaked the wording a bit here and there to address some of your feedback.

❤️ 2
borkdude 2023-12-24T11:38:57.730699Z

> The analyzer in clojure-lsp is absolutely stellar. This is clj-kondo btw ;)

1
1
borkdude 2023-12-24T11:41:16.394199Z

I think the REPL / static-analysis contrast is a false dilemma, it never occurred to me for a moment that static analysis would be used to replace a REPL, always in conjuction.

borkdude 2023-12-24T11:44:12.555769Z

People never write these kinds of articles about Cursive, while it's offering the same kind of combination and this was never controversial AFAIK

pez 2023-12-24T11:47:15.458179Z

I don’t think it really is about someone thinking lsp can replace the repl. It’s about the overlap, where the repl is used to do things that can also be done statically. And in that overlap we sometimes get different results. The repl reflecting the running application, and the static analysis reflecting what’s on disk (or perhaps what’s in the buffer, depending).

borkdude 2023-12-24T11:49:36.397579Z

> Case for CIDER: Powered by a the classic REPL-driven Lisp approach Well actually, nREPL isn't the classic REPL driven approach, the n part of nREPL is where the controversial part of that thing is ;)

borkdude 2023-12-24T11:51:17.431879Z

> In general I think that clojure-lsp is the clear winner until you decide to start a Clojure REPL. This is where I read a false dilemma. clojure-lsp (via clj-kondo) provides features nREPL cannot provide, like jumping to locals, renaming, locals, many many more things. Also syntax stuff that the REPL would choke on with impossible to read error messages. static analysis isn't a winner or loser, seeing them in competition is where the fallacy lies imo

pez 2023-12-24T11:51:19.981319Z

I think Cursive (and Calva) somewhat dodges the question because the users do not really need to ponder this much. The decisions are mostly taken. But at least for Calva users there is a bit of confusion, since the users haven’t configured this themselves, when things act a bit surprisingly it can be a bit hard to understand where the thing is happening.

borkdude 2023-12-24T11:53:48.860679Z

Btw, setting up a ClojureScript REPL (with normal CLJS) has always been very painful for me, to the point that I've completely given up on that and I'm happy I still have clojure-lsp to navigate around the code base, while relying on hot-reloading for actually running the app. I don't know how the situation is for shadow-cljs and nREPL, it probably works.

pez 2023-12-24T11:53:51.130009Z

I think that if you have CIDER configured and working, it becomes a question wether it’s worth bothering with configuring clojure-lsp as well, since you get very far with CIDER alone. The answer will vary from person to person, and probably from situation to situation as well.

pez 2023-12-24T11:55:32.534239Z

CLJS + nREPL works like a charm together is my experience. I often disable hot reload because I want better control on what’s running.

👍 1
borkdude 2023-12-24T11:55:43.602219Z

sure. I've been using CIDER + https://github.com/borkdude/flycheck-clj-kondo for a long time before I started using clojure-lsp. There is not much to configure to get the extra static analysis and overlaps even less with CIDER since it only provides diagnostics. Maybe this could be mentioned as a third option

borkdude 2023-12-24T11:56:56.582869Z

@pez for Node.js I can imagine that, but you also disable hot-reload for front-end?

pez 2023-12-24T11:58:12.730869Z

Yes. I configure a keyboard shortcut for calling the entry point and use that on demand when I want my compiled changes to take effect.

👍 1
borkdude 2023-12-24T11:58:35.123839Z

that's cool

pez 2023-12-24T11:59:32.624879Z

I guess I could configure shortcuts that do this every time I compile something top level. 🤔

vemv 2023-12-24T12:18:53.971969Z

While it's not necessarily a dilemma, for most users it is, because understandably, people don't necessarily want to learn about the intricacies of two separate tooling families, with their differences, tradeoffs and constant evolution. For most people it's a choice - they won't create (myself included) something that e.g. mixed and matched features - particularly observing the repl connection state to pick one particular implementation. It's something that would be, mostly, in our hands to improve - I'd look forward for that to happen someday 🙂

borkdude 2023-12-24T12:20:58.486649Z

btw slightly off topic, I don't know who maintains clj-refactor nowadays, but it seems the latest version asks for a :version op even when the server doesn't implement the op (i.e. not present in describe). I had to uninstall it to make CIDER work again with scittle's nrepl

vemv 2023-12-24T12:21:55.117489Z

I do - never heard of that!

bozhidar 2023-12-24T20:28:39.956279Z

> This is where I read a false dilemma. clojure-lsp (via clj-kondo) provides features nREPL cannot provide, like jumping to locals, renaming, locals, many many more things. Also syntax stuff that the REPL would choke on with impossible to read error messages. static analysis isn’t a winner or loser, seeing them in competition is where the fallacy lies imo Well, I wrote the article mostly because I’ve noticed that people wonder if they should use one tool or another, instead of using them together.

bozhidar 2023-12-24T20:29:34.594499Z

> In general I think that clojure-lsp is the clear winner until you decide to start a Clojure REPL. Well, technically speaking that’s true, just because without starting a REPL CIDER can’t do much for you. 😄

bozhidar 2023-12-24T20:30:41.258169Z

But I agree that’s a fairly nuanced topic and perhaps it would have been framed better as a comparison of static analysis vs runtime analysis.

bozhidar 2023-12-24T20:32:26.885709Z

> Well actually, nREPL isn’t the classic REPL driven approach, the n part of nREPL is where the controversial part of that thing is ;) I meant that in the sense of using a REPL for runtime analysis. It doesn’t really matter much what the exact REPL is - SLIME itself didn’t use a vanilla Common Lisp REPL, but rather it’s RCP REPL called swank.

bozhidar 2023-12-24T20:32:58.165359Z

But I totally get how this might be confusing.