Fork me on GitHub

If A depends on B, and my project depends on A and B but doesn't really care about the version of B as long as it's compatible with A, how should I specify this dependency on B in deps.edn? Or should I just omit the dependency on B from deps.edn?


I would figure out what version of B your chosen version of A depends on and explicitly specify that in deps.edn -- and add a comment about the version selection reason. Assuming you mean that your project has an explicit dependency on B.


That was exactly my thought initially. But now that I've given it some thought - wouldn't it be more practical to just omit it altogether? If A starts to depend on a different version of B, I should be unaffected, and I won't need to change anything. If A drops the dependency, the code will just not run because there's an explicit :require. And specifying B in my deps.edn seems like just giving myself more work when I update my dependencies.


If A changes the version of B it depends, it also changes its own version -- so unless you are changing the version of A you depend on, you wouldn't be affected 🙂


That's my point: if you choose to depend on a newer version of A, you should also verify the compatibility of the newer version of B that it now depends on as well. Having an explicit dependency on B lets you force the earlier version of B if you need that.


If A stops depending on B, that also means a new version of A and you could decide to stay with the old version or move to the new version -- and because you have an explicit dependency on B, you code won't break (at least, not because A's transitive dependency on B went away).


I really don't like relying on transitive dependencies. I much prefer to have all my dependencies listed explicitly. I've learned that over the years after a decade of Clojure in production 🙂


Hmm, I think I didn't give enough context. I definitely agree with your reasoning about the generic case of relying on a transitive dependency. But in my particular case, the code should either break completely if B is changed/removed, or it should continue working just as I expected it to. So the compatibility with my project is not a concern. At the same time, if I manage to forget to update B after updating A, I may introduce some incompatibilities between A and B that are hard to test.


To be more concrete - I'm just using ring.util.mime-type/ext-mime-type function without having an explicit dependency on ring/ring-core.


Of course even such a dead simple function can potentially be broken with an update. But I consider it so improbable that it's not worth taking into account. Akin to how I don't expect clojure.core/map to suddenly start giving me different results.


But you have code in your project that depends on Ring namespaces?


To be concrete, what are A and B specifically in your project?


A - yada/core B - ring/ring-core I need only ring.util.mime-type/ext-mime-type from B, which I consider stable in a sense that any changes around it either break the app startup or don't affect the app at all.


I don't depend on anything ring-related but that small function.


Ah, OK. If that is the only Ring namespace you're touching then maybe I would agree and just depend on Yada. It still feels a bit sketchy to me. We depend on Ring and we don't use that var -- we have our own MIME type structures (because we want a specific set of supported values, rather than a generic list).


I wish I would have a specific set. :) Yeah, I can see how it can feel sketchy. I'm still not sure about the way I work with my dependencies at all right now, given that there's also CLJS and a build process that involves shadow-cljs. Maybe this all could be made nice and simple with aliases. An unrelated to the rest of the thread question - aliases cannot be grouped together under a new alias, right? So I will probably have to write a script to call clj -A:al1:al2:al3.


Nope. Grouping of aliases is a common request.


I see. Anyway, thanks for the input Sean. Much appreciated. :)


It's why at work we have a build shell script that wraps the clojure script so we can have "higher-level" aliases.


Right, I've seen this pattern before. Sometimes even with -Sdeps, to avoid cluttering the main deps.edn I guess or to make the script more portable.


Our build script serves two purposes: to allow us to run a series of clojure commands from a single invocation, and to provide various shorthands for common combinations of aliases (our aliases tend to be very granular). But we're all Clojure / backend. I suspect if we were managing ClojureScript as well, we'd be even more reliant on our wrapper script!


I'm looking forward to -- I suspect it will help simplify our tool chain quite a bit.


I don't think I've heard of it and I can't find anything that seems relevant. Is there an announcement or something like that?


Alex mentioned it in an Inside Clojure blog post and has mentioned it several times here.


Heh, found it: " - shh, top secret"


Giving Cognitect's solid track record of producing simple, well-considered, composable tooling that addresses core Clojure developer needs, I'm looking forward to whatever this turns out to be 🙂

👍 3