Fork me on GitHub
#beginners
<
2024-07-04
>
Oscar Vargas Torres03:07:44

Hi! Is there a simple way to use global dependencies for my local clojure projects? I've been trying to follow guidance from LLMs, but it's not working for me. I created a "hello-world" application with the template https://github.com/seancorfield/deps-new?tab=readme-ov-file#create-an-application

clojure -Tnew app :name oscarvarto/hello-world
My plan is to get the reload functionality from https://github.com/tonsky/clj-reload available from Emacs in all my projects, without having to repeat configuration for each of them So, I created a ~/.clojure/deps.edn with the following contents:
{:deps {io.github.tonsky/clj-reload {:mvn/version "0.7.1"}}}
LLMs suggested to use something like:
:deps {org.clojure/clojure {:mvn/version "1.11.3"}
       #merge [io.github.tonsky/clj-reload]}
I may be making a very silly/newbie mistake, because I get:
> clojure -X:run-x
Error building classpath. Error reading edn. Map literal must contain an even number of forms (/Users/oscarvarto/clojureDev/hello-world/deps.edn)
Is the LLM's suggestion wrong altogether, and such a thing as declaring common dependencies with deps.edn doesn't exist?

Ben Sless04:07:09

The LLM is so wrong it's just wholesale hallucinating

Ben Sless04:07:07

I recommend starting with the official docs, then maybe referring to the Practicalli guides

Ben Sless04:07:55

There are no global dependencies in clojure, but you can create a global alias and inject it to all your REPL start commands in emacs

Oscar Vargas Torres04:07:21

Maybe I haven't seen the right spot in the docs.

Ben Sless04:07:26

I don't remember the emacs var name I'll check when I'm at the computer

Oscar Vargas Torres04:07:22

So, there is no such a thing as ~/.clojure/deps.edn?

Ben Sless04:07:19

There is, that's where you can add the reload dep under an alias https://clojure.org/reference/clojure_cli#deps_sources

Ben Sless04:07:28

Put the reload dependency under an alias, for example :dev/reload, then in emacs set the CLI default aliases to a string which will include it

Oscar Vargas Torres04:07:04

I have defined my $XDG_CONFIG_HOME, as ~/.config, so my default user deps.edn is actually in other place: ~/.config/clojure/deps.edn

👍 1
Oscar Vargas Torres05:07:04

I tried adding this to my Emacs config:

(setq cider-ns-code-reload-tool 'clj-reload)
(defun my-clojure-mode-hook ()
  (setq cider-clojure-cli-global-options "-A:dev/reload")
  (setq cider-repl-init-code "(do (require 'clj-reload.core) (clj-reload.core/init {:dirs [\"src\" \"dev\" \"test\"]}))"))
(add-hook 'clojure-mode-hook 'my-clojure-mode-hook)

(defun my-cider-reload ()
  (interactive)
  (cider-interactive-eval "(clj-reload.core/reload)"))
(with-eval-after-load 'cider
  (define-key cider-mode-map (kbd "C-c r") 'my-cider-reload))
to try to execute the initialization of clj-reload as described in the docs: https://github.com/tonsky/clj-reload?tab=readme-ov-file#usage But I got the following error message:
[nREPL] Starting server via /opt/homebrew/bin/clojure -A:dev/reload -Sdeps \{\:deps\ \{nrepl/nrepl\ \{\:mvn/version\ \"1.2.0\"\}\ cider/cider-nrepl\ \{\:mvn/version\ \"0.49.1\"\}\ refactor-nrepl/refactor-nrepl\ \{\:mvn/version\ \"3.10.0\"\}\}\ \:aliases\ \{\:cider/nrepl\ \{\:main-opts\ \[\"-m\"\ \"nrepl.cmdline\"\ \"--middleware\"\ \"\[refactor-nrepl.middleware/wrap-refactor\,cider.nrepl/cider-middleware\]\"\]\}\}\} -M:cider/nrepl
[nREPL] server started on 54556
[nREPL] Establishing direct connection to localhost:54556 ...
[nREPL] Direct connection to localhost:54556 established
error in process filter: string-join: Wrong type argument: sequencep, 40
error in process filter: Wrong type argument: sequencep, 40

Ben Sless05:07:32

That's an emacs error, can you get the back trace?

seancorfield06:07:32

Please, don't go down the reload path 😞 Just get into the habit of eval'ing every top-level form you edit. You do not need all this reload/refresh stuff -- it just papers over a bad REPL workflow 😞

Ben Sless06:07:16

Perhaps you could elaborate on why?

seancorfield06:07:27

It adds "easy" -- complex -- "magic" instead of learning the fundamentals of a REPL-based workflow. It's not like this is a new discussion here...

seancorfield06:07:46

These reload/refresh libraries are a crutch...

vemv06:07:21

It's just automation, not magic. clj-reload is a new lib so much of the usual criticism doesn't apply - usual bugs are now absent

seancorfield06:07:31

(and stop using LLMs to "help" you -- ask here instead: Clojure is a niche technology and LLMs are woefully incapable of answering questions about it, despite what a few people might say)

seancorfield06:07:36

@vemv It's an automation that experienced developers might understand -- but for beginners, it is "magic" and I really very forcefully disagree with encouraging beginners to use that sort of thing.

seancorfield06:07:33

I've been doing Clojure in production for over 13 years and I do not use reload/refresh and actively campaign against it.

vemv06:07:17

I've done plenty of merits for about the same time. Pretty sure someone else could boast about N years of experience and say for instance that Clojure is the worst thing ever... I'd just treat users, 'old' and new with the same respect, for example LLMs give me plenty of value (even if out of whack at times 😄), I assume most programmers are able to do a discerning choice about them Anyway, back to more fruitful matters myself... Oscar, you can continue the thread over here or #C0617A8PQ

seancorfield06:07:14

> I assume most programmers are able to do a discerning choice Most senior programmers, yes. Beginners not so much.

Ben Sless06:07:44

Whenever we discuss the merits of a certain tool or workflow, we always have to account for time in the saddle. What's good for a fresh eyed and bushy tailed developer might be a hindrance, setback or annoyance for a grumpy, experienced senior, and vice versa. This always runs up against any language, tool, library & aspiring for wide adoption and accessibility. I don't have a solution I'm mostly complaining

seancorfield06:07:51

> I don't have a solution I'm mostly complaining ❤️

seancorfield06:07:21

Just to be clear, even when I was a Clojure newbie back in 2010, after Amit Rathore's weekend workshop, I never felt the need for reload/refresh and always viewed it as a poor substitute for a good REPL-based workflow. My 13+ "time in the saddle" has just reconfirmed that 🙂

seancorfield06:07:53

(yes, this is the hill I'm prepared to die on!)

vemv06:07:14

As far as cider is concerned, both workflows are supported, and can be freely mixed and matched. I also encourage people to understand the conceptual underpinnings of both choices, which is exactly what happened yesterday: https://clojurians.slack.com/archives/C0617A8PQ/p1720048154592829?thread_ts=1720043873.647119&cid=C0617A8PQ I don't appreciate a lot this specifific activity of yours especially in the face of new tech. It represents hard, collaborative work, from Tonsky's clj-reload itself, to our integration in cider, and so on. We'd like the fair chance to see it flourish, as it deserves. In most contexts it's not quite a welcome opinion to say that so-and-so lib is 'bad' - I wouldn't imagine that happening too often in Clojurians Slack.

Oscar Vargas Torres10:07:00

I don't work at an office (working remotely for several years now). So, getting some help from a welcoming digital community is great guys. Thanks. And that's another reason I try to get some help from LLMs too. I don't always receive help/guidance from real people, so I am sometimes on my own, striving to learn by myself (and I will do it).

Oscar Vargas Torres10:07:07

I don't think experimenting with stuff is a bad thing.

❤️ 1
Oscar Vargas Torres05:07:04
replied to a thread:Hi! Is there a simple way to use global dependencies for my local clojure projects? I've been trying to follow guidance from LLMs, but it's not working for me. I created a "hello-world" application with the template https://github.com/seancorfield/deps-new?tab=readme-ov-file#create-an-application clojure -Tnew app :name oscarvarto/hello-world *My plan is to get the reload functionality from https://github.com/tonsky/clj-reload* *_available from Emacs_ in all my projects, without having to repeat configuration for each of them* So, I created a `~/.clojure/deps.edn` with the following contents: {:deps {io.github.tonsky/clj-reload {:mvn/version "0.7.1"}}} LLMs suggested to use something like: :deps {org.clojure/clojure {:mvn/version "1.11.3"} #merge [io.github.tonsky/clj-reload]} I may be making a very silly/newbie mistake, because I get: > clojure -X:run-x Error building classpath. Error reading edn. Map literal must contain an even number of forms (/Users/oscarvarto/clojureDev/hello-world/deps.edn) Is the LLM's suggestion wrong altogether, and such a thing as declaring common dependencies with deps.edn doesn't exist?

I tried adding this to my Emacs config:

(setq cider-ns-code-reload-tool 'clj-reload)
(defun my-clojure-mode-hook ()
  (setq cider-clojure-cli-global-options "-A:dev/reload")
  (setq cider-repl-init-code "(do (require 'clj-reload.core) (clj-reload.core/init {:dirs [\"src\" \"dev\" \"test\"]}))"))
(add-hook 'clojure-mode-hook 'my-clojure-mode-hook)

(defun my-cider-reload ()
  (interactive)
  (cider-interactive-eval "(clj-reload.core/reload)"))
(with-eval-after-load 'cider
  (define-key cider-mode-map (kbd "C-c r") 'my-cider-reload))
to try to execute the initialization of clj-reload as described in the docs: https://github.com/tonsky/clj-reload?tab=readme-ov-file#usage But I got the following error message:
[nREPL] Starting server via /opt/homebrew/bin/clojure -A:dev/reload -Sdeps \{\:deps\ \{nrepl/nrepl\ \{\:mvn/version\ \"1.2.0\"\}\ cider/cider-nrepl\ \{\:mvn/version\ \"0.49.1\"\}\ refactor-nrepl/refactor-nrepl\ \{\:mvn/version\ \"3.10.0\"\}\}\ \:aliases\ \{\:cider/nrepl\ \{\:main-opts\ \[\"-m\"\ \"nrepl.cmdline\"\ \"--middleware\"\ \"\[refactor-nrepl.middleware/wrap-refactor\,cider.nrepl/cider-middleware\]\"\]\}\}\} -M:cider/nrepl
[nREPL] server started on 54556
[nREPL] Establishing direct connection to localhost:54556 ...
[nREPL] Direct connection to localhost:54556 established
error in process filter: string-join: Wrong type argument: sequencep, 40
error in process filter: Wrong type argument: sequencep, 40

Oscar Vargas Torres05:07:09

This is what I get in my ~/.config/clojure/deps.edn:

❯ cat ~/.config/clojure/deps.edn
{
  :aliases {
    ;; Add cross-project aliases here
    :dev/reload {:extra-deps {io.github.tonsky/clj-reload {:mvn/version "0.7.1"}}}
  }
}

Oscar Vargas Torres05:07:23

Please, bear with me. Trying to get a practical Repl (reload!) dev environment with (Doom) Emacs + CIDER for clojure.

Oscar Vargas Torres05:07:50

If anyone has a suggestion it will be very much appreciated. Will read your answers tomorrow. I'm totally exhausted right now 😴

shivang raina08:07:14

I have code that uses cond with multiple conditions. One of the conditions involves a database call, and if this condition is true, I need to use the value from the database call within my body. How can I incorporate let inside a cond condition to achieve this? I want to avoid doing the same db call in body

(cond (condition) (body..)
       (condition2) (body..)
       (db-call-condition) (let [value (db-call-condition)]))

daveliepmann09:07:06

is there a reason not to wrap the cond with the let?

shivang raina09:07:20

@U05092LD5 I want to avoid a db call if my above conditions are true.

👍 1
adi09:07:55

Several ways to do this... I would probably separate out a DB calling function, and gate it with a function that checks for the earlier conditions.

🙌 1
👍 1
adi09:07:18

Alternately: if your DB call is the last condition,

(cond 
  (c1) (do something)
  (c2) (do anotherthing)
  :else (when-let [v (db-call)]
          (do-last-thing-with v)))
(Of course, this means, the db-call should return nil if the query does not fetch results.)

shivang raina09:07:59

@U051MHSEK Thanks. Btw in my case it is not the last condition though.

👍 1
genmeblog11:07:50

Chain them:

(cond 
  (c1) (do something)
  (c2) (do anotherthing)
  :else (let [dbcc (db-call-condition)]
          (cond
            dbcc dbcc
            (c3) (do otherthings)
            (c4) (...))))

3
Ben Sless13:07:58

you might consider it ugly but

(let [call (delay (your-db-call))]
  (cond
    (c1) (body1)
    (c2 @call) (body2 @call)
    (c3) (body3)))

👍 3
3
adi05:07:02

The delay is neat! I'd say it is exactly what the doctor ordered for this... case (haha).

Oscar Vargas Torres14:07:34

Hey @seancorfield, I used your https://github.com/seancorfield/deps-new?tab=readme-ov-file#create-an-application to create a new application structure using deps.edn. I am also using CIDER. However, what I see is that when I do cider-jack-in , the repl doesn't start in my expected namespace (it starts with user >). That was not happening to me with a leiningen project. I tried adding

:repl-options {:init-ns oscarvarto.hello-world}
to my deps.edn, but this didn't work. Any suggestions?

seancorfield16:07:59

The Clojure CLI doesn't have :repl-options (and, personally, I've never understood the use of it in Leiningen).

seancorfield16:07:45

BTW, it's considered a bit rude to @ people unless it's in a thread where they already replied.

Oscar Vargas Torres14:07:05

JFYI, I am a Doom Emacs user.

vemv14:07:39

that's bit of a FAQ The sad answer is simply, you can't. Lein accomplished in bit of a hacky way which isn't replicated in tools.deps However you can run arbitrary code with cider-repl-init-code . You might also hack your Emacs init so that it changes the ns in the repl after a successful connection

jf15:07:44

I'm just now noticing this interesting statement over at https://clojure.org/guides/install_clojure, and wondering whether anybody's tried just setting JAVA_HOME, while leaving PATH alone. Have you encountered any issues?

The Clojure tools require only that the java command is on the PATH or that the JAVA_HOME environment variable is set.
Would this apply to all Clojure development (not exactly sure how to define "The Clojure tools")? to be sure, it's not a big deal adding java to the PATH; but if I can avoid it, I'd just prefer doing only JAVA_HOME if only 1 of the 2 is necessary.

Bob B15:07:47

The clojure script constructs the java command to run using $JAVA_HOME, so java being on $PATH isn't strictly relevant to using clj or clojure (and leiningen might be the same situation). Obviously, doing things like running a standalone jar using java -jar won't work in java isn't on $PATH , and more JVM-level things (e.g. adding certs to a keystore using keytool or using mission control or other tools that come with a JVM) require a little more qualifying if the java bin dir isn't on $PATH.

jf15:07:27

hm I guess you're right. I did have a look at the source of clj and clojure before asking, so I know I'm in the clear there.. but just wasnt sure about the impact on what else it means for "clojure development". I was hoping for a simple and straightforward answer, but I guess yes, i think it all depends on what u're doing and what that requires. Thank you for the note!

growthesque15:07:35

Noticed this nice custom implementation of flatten on 4clojure and was wondering what's the role of rest here. Seems like it works just the same without it. Is it some sort of optimization?

(defn my-flat [x]  (filter (complement sequential?)
                  (rest (tree-seq sequential? seq x))))

growthesque16:07:23

I guess since the first step of the sequence doesn't contain any useful information, person who wrote this dumps it. wondering if this is more optimal than simply working with the whole sequence.

Bob B16:07:14

I think it is just an optimization because the first item is the whole sequence to be flattened. Side note, the custom implementation appears to be exactly the same as clojure.core/flatten

🙏 1
growthesque16:07:42

noob question: Is recur not a first class citizen? How come I can't use it in this example instead of calling the fn by its name like I usually can?

(defn my-flat [c]
  (if (sequential? c)
    (mapcat my-flat c) ;; can't replace with recur here
    (list c)))

phronmophobic16:07:53

from https://clojure.org/reference/special_forms#recur > recur in other than a tail position is an error. > > Note that recur is the only non-stack-consuming looping construct in Clojure. There is no tail-call optimization and the use of self-calls for looping of unknown bounds is discouraged. recur is functional and its use in tail-position is verified by the compiler.

growthesque16:07:16

is mapcat in the tail position in this example?