I https://github.com/jacobobryant/biff/issues/249#issuecomment-3670796822 that setting a org.clojure/clojure version in a library doesn't actually do anything, at least when running a project with clj. In this case I have a library that needs clojure 1.12, so it includes that in its deps.edn. But if you have clj 1.11 installed and you try to run an application that depends on that library, you end up with 1.11 and thus get an exception. You have to put the org.clojure/clojure version in your project's deps.edn, not in the library's deps.edn. That's not a big deal in this case, but I'm still curious if that's an intentional behavior and what the rationale is if so? From some searching all I've found is https://ask.clojure.org/index.php/14112/way-specify-clojure-version-across-all-deps-files-monorepo (and the linked https://clojurians.slack.com/archives/C03S1KBA2/p1725756729831549?thread_ts=1725754474.109679&cid=C03S1KBA2) which was closed as a duplicate, however that question is specifically asking about setting a org.clojure/clojure version, and the question it was marked as a duplicate of doesn't cover that.
The general practice with libraries tends to be that you specify the oldest version that your library works with in its deps.edn and you note any minimum Clojure version in your README.
And with applications, you generally specify the version of Clojure you want to use.
Relying on the CLI install's default Clojure version is not recommended.
that's what I'm trying to do, specify the oldest version it works with in the deps.edn. but it doesn't work.
(in the library's deps.edn)
Right, but it's essentially "documentation".
In Maven, lein, and tools.deps the versions of top level deps specified in an application are used regardless of transitive versions specified via deps. This allows an app to have the final say, and to override a deps choices
The important thing to know is that libs never control the version of their deps used at runtime
right, I'm just curious why the handling of the org.clojure/clojure dep seems to be different from every other dep? Usually, if you don't set a version in your top-level deps.edn for some dependency, then the highest version dependended on transitively will be used. But for org.clojure/clojure, transitive versions are ignored. If it's recommended that projects should always set an explicit org.clojure/clojure version, that seems reasonable, in which case I suppose this behavior doesn't really matter. But I'm still curious if it's intentional, and why if so. Maybe it's just an implementation quirk from clj?
There are three sets of deps: root, user, and project. The root version of Clojure is whatever the CLI default is. So it acts as a top-level dep. That's my understanding of it.
Correct
It's special in that it's always a top level dep via the root deps
The root deps.edn is essentially:
{
:paths ["src"]
:deps {
org.clojure/clojure {:mvn/version "1.12.4"}
}
:aliases {
:deps {:replace-paths []
:replace-deps {org.clojure/tools.deps.cli {:mvn/version "0.14.121"}}
:ns-default clojure.tools.deps.cli.api
:ns-aliases {help }}
:test {:extra-paths ["test"]}
}
:mvn/repos {
"central" {:url " "}
"clojars" {:url " "}
}
}
(for CLI 1.12.4.1582)This is intentional because clj is a Clojure program runner and it always invokes some Clojure program so it needs Clojure on the classpath
(but it's baked into the tools uberjar as a resource so the installed deps.edn is not used, even tho' it is still shipped)
Ok, that makes sense. In terms of implementation/why it's happening, at least. I'm still not sure about should-this-be-happening...
> This is intentional because clj is a Clojure program runner and it always invokes some Clojure program so it needs Clojure on the classpath
Theoretically this could be implemented in some way where the org.clojure/clojure dep from clj wasn't treated as a top-level dep, right? In which case, if the user's project doesn't specify a clojure version, then the latest version from either clj or any transitive deps would be used.
In this case (biff) since I control the new project template, it's easy for me to stick a org.clojure/clojure dep in there. But if this were a "regular" library and a user hadn't set a clojure version in their project's deps.edn, it seems like it would be a better user experience for clj to use a higher-than-default clojure version (i.e. the version specified transitively) rather than the user getting an exception when the library code doesn't compile?
Perhaps the "solution" here is for the CLI to be more active in encouraging users to upgrade? The first 1.12 CLI came out well over a year ago: 1.12.0.1479 (Sep 5, 2024).
and/or maybe have it print a warning if you're using a project-level deps.edn file that doesn't specify a clojure version?
I expect that to be a common case (including for non-project uses cases), so not want to warn there
Given the root <- user <- project deps.edn merging, I'm not sure how the CLI would be avoid treating the root deps as "top-level"...
I don't think the warning would be a good UX for beginners: https://clojure.org/guides/deps_and_cli shows that you only need the "additional" libraries. Being able to run a REPL with nothing, but then having to specify Clojure in deps.edn as soon as you create it seems... confusing and burdensome?
Could the CLI check for the latest CLI version and if it differs in the main Clojure version, suggest that the user upgrade? (obvs this can only be done once the user has already upgraded to a version that includes this check)
> Given the root <- user <- project deps.edn merging, I'm not sure how the CLI would be avoid treating the root deps as "top-level"...
seems like an easy hack would be to have the root deps.edn depend on some wrapper/shell library which then in turn depends on org.clojure/clojure ?
we have an open enhancement about adding upgrade check + warn. some people are opposed to this as they don't want the CLI doing extra network traffic (particularly relevant in containers and CI etc). having some way to ask for the check seems like an obvious add, but I'm on the fence about automatic checking
> seems like an easy hack would be to have the root deps.edn depend on some wrapper/shell library which then in turn depends on org.clojure/clojure ?
this is one option I've been considering for tools, which have the occasional problem where a tool wants a newer version (like an upcoming alpha) than what is available. right now, it's not possible to do get that in a tool due to how the classpath is formed.