This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-11
Channels
- # announcements (6)
- # architecture (9)
- # beginners (120)
- # calva (13)
- # cider (28)
- # clj-kondo (8)
- # cljs-dev (7)
- # clojure (113)
- # clojure-europe (13)
- # clojure-italy (7)
- # clojure-nl (9)
- # clojure-spec (44)
- # clojure-uk (7)
- # clojuredesign-podcast (15)
- # clojurescript (18)
- # cursive (9)
- # data-science (3)
- # datomic (32)
- # defnpodcast (1)
- # events (2)
- # fulcro (6)
- # jobs (1)
- # kaocha (5)
- # london-clojurians (2)
- # luminus (2)
- # nyc (2)
- # off-topic (54)
- # ring (6)
- # shadow-cljs (136)
- # sql (1)
- # testing (2)
- # tools-deps (64)
- # vim (83)
If my lib makes use of a dep, but I fully expect the users of the lib to also make use of that dep, it made sense logically to not include those deps as transitive dependencies. But I lack a full understanding of how t.d. resolves conflicts…
this is certainly under-documented
In general, I think it makes sense for a lib to include all the dependent libs it needs in its explicit dependencies
the way tda resolves conflicts is generally to pick the newest version
with the caveat that it picks whole subtrees and in some cases that upstream libs higher in the tree may dominate
however, one big hammer is that the versions at the very top (presumably the app) always win
so the end user always has final say
so if the app includes both your lib and the datomic cloud-client lib, then it's explicitly naming the datomic lib and that version will be used, which is what you want here
let me know if that doesn't make sense
Okay, that makes sense, thanks. Explicit deps are certainly much simpler as well. It’s nice to be able to lean on t.d.a. a bit there.
I’m going to remove my :provided
alias for now and just go with the simplest solution. Thanks, Alex.
@dominicm is there a t.d. way to do that? Best I’ve seen people do is add a conditional flag surrounding calls to s/def
…
t.d way to do what?
@alexmiller to optionally also bring in the specs…I’m not sure exactly what that would mean honestly. Potentially some way to specify a dependency along with additional aliases, like:
:deps {me/sweet-dep {:mvn/version "XYZ" :aliases [:specs]}}
but this is potentially not practical, or even desirable.@cjsauer clojure.java.jdbc
and next.jdbc
have "optional specs" -- they have them in a separate namespace in the project and if you want to use them, you just require
the *.specs
namespace. That allows the projects to run on Clojure versions older than 1.9 (i.e., before spec was created) but the specs are still bundled with the project/artifact.
or put them in separate libs, but that's a lot more work
(well, next.jdbc
requires at least Clojure 1.10 because it depends on clojure.datafy
but I could probably make that feature optional as well)
My time in web dev forces this desire to keep the dep small in size…but for jars that really doesn’t matter I suppose… For example, in this datomic ions lib I’m working on, I have an example project included in a separate source folder. I toyed with ideas for not including it in the final artifact, but there’s really no gain from that effort (and it would even prevent me from deploying the example, because ions uses your top-level deps, i.e. it doesn’t take aliases into account)
Not to mention that the cljs compiler will strip any unused code out anyway. My brain is still catching up to these awesome tools 😅
I'd probably create a separate project for the example stuff that depended on your main project and then just document it copiously in the main project. But, as you say, source is tiny so shipping an example in the main project doesn't hurt as long as it's all in separate namespaces that users can ignore if they aren't interested in it.
Also, you can have a git dependency that uses a subfolder of the repo -- which might be another was to offer it as an example to folks?
:deps/root
It actually was a separate repository, but it made developing the lib such a pain because changes are happening rapidly at the moment. It’s likely something that can be extracted once the API stabilizes tho.
Yes, it goes with :git/url
to tell t.d.a. to navigate into the specified location within the repo.
Interesting…I might have to try that. What is the REPL experience like with this? It’d be great to be able to eval things and have the example pick them up instantly.
"It’d be great to be able to eval things and have the example pick them up instantly." -- that is what I would expect with an RDD workflow.
When I'm working on a project, I do everything via the REPL. So I either start the apps/services from inside the REPL, or I add the JVM options to start a Socket REPL when the app/service starts up (such as on QA/production). Then I connect my editor to that REPL and eval code as I go, so changes are picked up immediately by the running apps/services.
We sometimes apply hot fixes to production processes that way -- zero downtime 🙂
Bold! But let’s say one of your services depends on either a :local/root
or deps/root
dependency, and you realize you need to make a change in that dep. Can you do that easily without rebooting the REPL?
In Cider I can jump into a lib that isn’t mine part of the current project, and make changes and eval them, and it works, but obviously those aren’t “saved” in the traditional sense
I’m sure this becomes much less of an issue once the lib begins to stabilize. At the moment, my example serves as something of a test bed, so changes between the two are happening constantly. The convenience of having both in the same deps project is really nice, but it’d become less useful as the lib changes slowed.
When they were in separate repos, I found I was having to reboot my REPLs often. There might be a better way tho. Especially with :local/root
, which I admittedly haven’t experimented with much.
I'm not quite sure what you're asking. If you evaluate code into the REPL, the changes take effect immediately. So, yeah, if you have the source of the lib you're depending on, you can edit it and evaluate it into your REPL without needing to restart it.
When you're developing stuff locally and you're code is still volatile, you can use :local/root
to point to the folder the source is in and just edit/eval it into the REPL you're already using for your example project.
Maybe this is a limitation of cider. REPLs in cider seem to be “scoped” to the current project. If I open the source file of another folder, I no longer seem to have a REPL connected :thinking_face:
@U04V70XH6 suddenly I see why my questions make no sense…all this time everyone else has been eval’ing arbitrary source code.
I assume that's to do with CIDER's ability to work with several open REPLs, one for each "project"? I remember when I switched from Emacs/CIDER/nREPL to Atom/ProtoREPL (three years ago) at first I was annoyed that ProtoREPL didn't let me just switch between multiple REPLs but over time I just adopted a workflow where I can work in one REPL across multiple projects -- and now I tend to run a single "everything" REPL for days or even weeks, and just eval in any source code I need to work with.
(and I'm now figuring out how best to work with add-lib
on the t.d.a. branch so I don't even need to restart a REPL to add new library dependencies)
CIDER actually had that functionality way back when, I really miss it. Hot-loading deps was super convenient.
I have a :deps
alias with the add-lib
branch and then
(require '[clojure.tools.deps.alpha.repl :refer [add-lib]])
and then (add-lib 'some/new-lib {:mvn/version "RELEASE"})
and it downloads the new library and then it can be required.What I was missing was two lines of code to set up a DynamicClassLoader immediately before starting my Socket REPL and REBL (I have a small ws.dev.repl/-main
function for doing that, based on what it finds on the classpath).
(I've already opened an issue against REBL to suggest that it starts its REPL in a DCL)
Hmm, I don't use CIDER.
I use Atom with Chlorine so I can use simple Socket REPLs with no additional dependencies in my code.
So, for me, there is "only one REPL" and I can evaluate any and all code into it. I like simple tooling. CIDER is not simple. nREPL is not simple.
Stu Halloway was interviewed on the ClojureScript podcast about his REPL usage and he uses really minimal tooling (a plain REPL with inferior mode in Emacs I think he said). I think Rich is the same.
Chlorine gives me auto-complete using just the built-in features in Clojure, which I also like (it used to require Compliment for that -- which is also part of CIDER/nREPL).
It's also why I was so happy to switch from lein
/`boot` to the new CLI/`deps.edn` stuff. Simple tooling.