tools-deps

Discuss tools.deps.alpha, tools.build, and the clj/clojure command-line scripts! See also #depstar #clj-new
seancorfield 2020-07-29T01:15:01.249600Z

(OK, running 1.10.1.596 on all our servers at work now ๐Ÿ™‚ )

salam 2020-07-29T01:50:42.250200Z

how would one represent this in deps.edn?

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc-bom</artifactId>
      <version>19.7.0.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc10</artifactId>
   </dependency>
</dependencies>

salam 2020-07-29T01:51:37.251Z

if possible, of course.

salam 2020-07-29T02:00:49.252500Z

for the context: https://www.oracle.com/database/technologies/maven-central-guide.html#DIY

seancorfield 2020-07-29T02:03:42.253300Z

@abdusalam Pretty sure you'll need to figure out what that Bill Of Materials expands to and add each of those dependencies directly to deps.edn

salam 2020-07-29T02:06:25.254800Z

thanks, Sean. does it mean there's no direct, built-in support in tools.deps for this kind of use case?

seancorfield 2020-07-29T02:25:55.255400Z

Not as far as I'm aware.

alexmiller 2020-07-29T02:35:27.255900Z

no, deps does not support the BOM / import scope stuff

alexmiller 2020-07-29T02:38:33.256900Z

it seems radical, but deps just expects you to list the specific dependencies you're using :)

๐Ÿ˜‚ 1
salam 2020-07-29T03:03:00.263900Z

i see. oracle's jdbc driver (com.oracle.database.jdbc/ojdbc10) used to list other "extra goodies" as dependencies in its pom.xml. i was looking for an elegant way to exclude the extra stuff in order to avoid doing the "exclusion dance" but just found out that it's dropped all of the dependencies since version 19.7.0.0. all we need to do now is to add com.oracle.database.jdbc/ojdbc10 {:mvn/version "19.7.0.0"} to get just the driver itself. ๐Ÿ™‚

salam 2020-07-29T03:03:49.264100Z

all good now

alexmiller 2020-07-29T03:23:20.265Z

yeah, that's all most people need. the whole bom thing seems like something an enterprise java developer thought up while they were high

๐Ÿ˜† 7
2020-07-29T06:54:50.271600Z

So I really appreciate the expanded deps guide and reference, but there are two things from the previous iteration of the docs that I found useful that appear to have disappeared now: One was the old deps data-flow/arg/alias mapping diagram: https://github.com/clojure/clojure-site/blob/master/assets/images/content/guides/deps/deps.png which I appreciate might now either need to be two diagrams, or reworked into a more complex one. Whilst itโ€™s not something I used often, I thought it was effective in the guide at showing what aliases influenced each phase of execution etc. And the other perhaps more importantly was the โ€œAliasesโ€ section in the old docs here: https://github.com/clojure/clojure-site/blob/285fda270445a70af9b1ec7bdb069309d2d224d7/content/reference/deps_and_cli.adoc#aliases which clearly described how keys in a deps file were used by the command line alias flags. Are there any plans to bring updated versions of these sections back?

alexmiller 2020-07-29T14:05:30.290200Z

the docs are (always) a work in progress. I pulled the diagram b/c it was way out of date. I have updated it a number of times during the process of the basis changes but I have concerns about whether it actually provides that much value as it has grown increasingly complicated. All of the info from the old Aliases section is still in the doc.

๐Ÿ‘ 2
onetom 2020-07-29T19:50:14.354Z

i found that diagram quite helpful, when i was initially learning the clojure cli. in practice however, i never really had to use anything else then -A so far...

2020-07-29T07:02:02.276Z

Second question โ€” how stable are the new features in tools.deps? In particular the -X feature and the args map data? Are they likely to experience breaking changes between now and the next stable release? I get the feeling not. Sometimes itโ€™s not clear to me what is blessed as stable and isnโ€™tโ€ฆ i.e. the installer, the command line args, or the tools.deps api. (Though I guess itโ€™s all technically alpha because itโ€™s t.d.a not t.d)

thheller 2020-07-29T10:46:17.278300Z

@alexmiller how come you are dumping all the new features into :aliases? kinda confusing to give aliases multiple meanings IMHO. maybe I'm just not seeing the bigger picture though.

thheller 2020-07-29T10:53:23.279400Z

like why is the exec stuff in :aliases and not a new top-level :exec key or so?

borkdude 2020-07-29T11:05:46.280100Z

as far as I have understood it: :aliases was always intended for naming a chunk of EDN data that could be re-used elsewhere, but it's only now that we can see that being used in more places

borkdude 2020-07-29T11:06:54.280400Z

I wonder if you can combine -A and -X to include extra deps in an -X invocation

alexmiller 2020-07-29T13:06:32.281300Z

you can, absolutely

alexmiller 2020-07-29T13:06:44.281500Z

that's kind of the idea

alexmiller 2020-07-29T13:09:08.282Z

should be stable unless we discover some reason to change. not expecting to discover anything but that's why we're letting people try it. I'm expecting the gap to stable to be like days, not a long time.

๐Ÿ‘ 1
2020-07-29T13:51:23.283300Z

:thinking_face: so you can change the function that executed with the default data (by changing the classpath via :extra-deps); but you canโ€™t change the data for a function alias

alexmiller 2020-07-29T14:00:51.285700Z

I'm not sure that's "changing the function" as much as supplying the function

alexmiller 2020-07-29T14:00:58.286100Z

and you can override the data on the command line

alexmiller 2020-07-29T14:01:07.286500Z

maybe I'm not getting what you're describing

2020-07-29T14:02:04.287300Z

is that intended usage? It feels a bit weird to have the same fully qualified function name, but with two different definitions (in two different :paths for example). Would it not be more natural for -X :args to compose?

alexmiller 2020-07-29T14:02:25.287900Z

I don't understand why you have that

alexmiller 2020-07-29T14:02:52.288400Z

can you more fully describe what you're talking about, because I don't get it

vlaaad 2020-07-29T14:10:30.295500Z

@rickmoynihan you mean something like that?

{:aliases {:deploy-to {:fn my.ns/deploy}}
           :prod {:args {:url "<http://prod.com|prod.com>"}}
           :qa {:args {:url "<http://qa.com|qa.com>"}}}
clj -X:deploy-to:prod

2020-07-29T14:11:27.296700Z

Yeah sorryโ€ฆ I think I misinterpreted the motivation behind what @borkdude was saying as a way of effectively doing what @dominicm was asking earlier about composing :args data. But I misread :extra-deps as being :deps. Either way it seems :deps would kind of allow the kind of thing @dominicm was asking for; but in a nasty wayโ€ฆ i.e. you could swap the function rather than the data. e.g. - clj -A:myfn -X:args - clj -A:myfn2 -X:args Where myfn and myfn2 aliases defined the same ns but with different function definitions.

2020-07-29T14:11:34.297Z

Not saying this is a good idea btw!!!

alexmiller 2020-07-29T14:12:06.297500Z

one helper here is that :args can also refer to an alias instead of a map

2020-07-29T14:12:22.298Z

oh rightโ€ฆ that is interesting!

2020-07-29T14:12:46.298500Z

seems more useful than the :paths one

alexmiller 2020-07-29T14:13:34.299Z

well the :paths one is foreshadowing :)

alexmiller 2020-07-29T14:14:14.300300Z

I did forget to mention that in my blog writeup, but I think it's in the docs

2020-07-29T14:14:56.300500Z

yes

alexmiller 2020-07-29T14:14:57.300700Z

or maybe it isn't!

2020-07-29T14:15:19.301100Z

I donโ€™t recall seeing it

vlaaad 2020-07-29T14:15:28.301400Z

yeah, me neither

alexmiller 2020-07-29T14:15:38.301900Z

it was in some version of the docs but looks like it got lost in the N reworks I did

2020-07-29T14:15:45.302300Z

๐Ÿ˜† easily done

alexmiller 2020-07-29T14:15:47.302500Z

anyhow, that's a thing

2020-07-29T14:16:23.303200Z

wow โ€” I was silently disappointed that something like this wasnโ€™t there

2020-07-29T14:16:30.303400Z

but itโ€™s great that it is

2020-07-29T14:16:36.303600Z

is there an example of how it works?

vlaaad 2020-07-29T14:17:31.304Z

where else can I put aliases?!?!?!

alexmiller 2020-07-29T14:17:43.304200Z

data

alexmiller 2020-07-29T14:17:51.304400Z

it's just edn

alexmiller 2020-07-29T14:18:01.304600Z

oh sorry, misread your question

alexmiller 2020-07-29T14:18:57.305500Z

if you read https://insideclojure.org/2020/07/28/clj-exec/ check out the basis injection stuff there

alexmiller 2020-07-29T14:20:44.305700Z

I'm unclear if you have a question, and if so, what it is...

dominicm 2020-07-29T14:21:10.305900Z

Not a question, I already asked mine!

dominicm 2020-07-29T14:21:25.306100Z

Just clarifying that I don't think this would allow for multiple functions like on after :)

alexmiller 2020-07-29T14:23:44.306300Z

{:aliases
 {:f1 {:fn my/fn1
       :args :data}
  :f2 {:fn my/fn2
       :args :data}
  :data {:something :here}}}
and then clj -X:f1 or clj -X:f2

alexmiller 2020-07-29T14:24:45.306500Z

no

dominicm 2020-07-29T14:27:41.307700Z

Now we have runtime basis, does that mean you can go back and interpret the exec aliases however you like?

alexmiller 2020-07-29T14:36:11.308Z

you can write a program that uses alias data

alexmiller 2020-07-29T14:36:30.308400Z

which is broader than what you said

alexmiller 2020-07-29T14:37:14.308500Z

yeah, that's not a thing

alexmiller 2020-07-29T14:40:00.308700Z

I would probably do this:

{:aliases
 {:deploy-prod
  {:fn my.ns/deploy
   :args {:url "<http://prod.com|prod.com>"}}
  :deploy-qa
  {:fn my.ns/deploy
   :args {:url "<http://qa.com|qa.com>"}}}

๐Ÿ‘ 1
alexmiller 2020-07-29T14:40:20.308900Z

but there may be other variants depending on shared config, command-line overrides etc

alexmiller 2020-07-29T14:40:55.309100Z

also my.ns/deploy could interpret data in :args as something to look up in :aliases via the basis

alexmiller 2020-07-29T14:41:14.309300Z

you don't get that for free, but it's like 2 lines of code

alexmiller 2020-07-29T14:41:58.310Z

these 2 lines https://insideclojure.org/2020/07/28/clj-exec/#runtime-basis

vlaaad 2020-07-29T14:55:22.310600Z

Yeah, I get what you mean. Basis FTW!

seancorfield 2020-07-29T15:55:54.311200Z

I was surprised that 1.10.1.590 seems to be the latest stable version on brew already, given the flurry of bug fix releases yesterday (1.10.1.596 and 1.10.1.600).

seancorfield 2020-07-29T15:59:17.311400Z

The basis stuff looks very interesting, but you lose access to it if your build your artifacts as uberjars and run them via java -jar (although I guess you could still do -Dclojure.basis='{...}' ๐Ÿ‘€ )

seancorfield 2020-07-29T16:00:00.311600Z

It almost makes me want to go back to running code in production via clojure instead ๐Ÿ™‚

โ˜๏ธ 1
seancorfield 2020-07-29T16:03:06.313400Z

I asked in a thread, but I'll ask in the main channel for everyone to see: given that clojure.basis is a property added by the clojure command, what is the thinking behind leveraging this in production code if you normally build uberjars and run those with java -jar? All of that lovely combined deps.edn structure has gone by that point...

2020-07-30T09:11:14.370300Z

I also had a similar thought when I stumbled across the basis property etc. Though I figured you could spit out the basis to a clojure.basis file inside the uberjar, and slurp it as an io/resource in your -main. However the big disadvantage to this is that the basis would be generated at build time rather than run time, so it would be more like a manifest, than what the basis is really supposed to be. On reflection I think your idea is better โ€” though Iโ€™m not entirely sure what youโ€™d use the basis for in that case, other than as a means of using the clojure tool to provide config to your app.

2020-07-30T09:21:22.370900Z

I guess the only real advantage is using the clojure tool and a deps.edn to manage the classpath in production code, rather than the underlying java command line.

2020-07-30T09:25:40.371100Z

I have in the past done things like java -cp:myapp-uberjar.jar:some/server/resources/* myapp.main to for example add assets to an apps resource path as a production overlayโ€ฆ so I guess using the clojure tool itself to help manage these kind of things with aliases might be useful; though Iโ€™m not convinced the benefits are huge

2020-07-30T09:26:32.371300Z

though I guess it might sometimes be useful to for example provide profiles in production for enabling socket servers etc :thinking_face:

2020-07-30T09:30:38.371700Z

Also another usecase is you could provide extra tooling for prod systems in this manner. e.g. a set of aliases for various production tasks, e.g. triggering a -A:backup alias over cron etc.

2020-07-30T09:31:42.371900Z

and it would mean you donโ€™t need to waste time inventing new command line parsers and config formats etc

seancorfield 2020-07-29T16:04:13.314500Z

It almost feels like it's worth switching to using clojure to run uberjars via an alias in the deps.edn so that all that stuff remains available in a "production" style context...

ghadi 2020-07-29T16:04:24.314800Z

my guess is that an uberjar tool could convey the basis into the jar

ghadi 2020-07-29T16:05:17.316Z

the more I think about uberjars, the more disadvantages I see vs. sync'ing deps

seancorfield 2020-07-29T16:05:34.316500Z

The basis differs depending on the aliases used to run clojure tho', right?

seancorfield 2020-07-29T16:06:32.317800Z

(because the paths and lib map etc can be different from invocation to invocation -- although the set of aliases etc remains the same)

ghadi 2020-07-29T16:06:44.318Z

I'm shooting from the hip

ghadi 2020-07-29T16:07:35.319300Z

i'd mostly want the alias data

ghadi 2020-07-29T16:07:42.319500Z

for stuff like config

seancorfield 2020-07-29T16:08:38.320700Z

I'd add it to depstar but I think at this point I want to wait and see what tools.build ends up being ๐Ÿ™‚

๐Ÿฆœ 1
seancorfield 2020-07-29T16:11:08.321300Z

I might experiment with using clojure to run uberjars tho' later today puts on mad scientist hat...

1
ghadi 2020-07-29T16:11:22.321500Z

wdym?

ghadi 2020-07-29T16:12:27.322800Z

using clojure instead of uberjars?

seancorfield 2020-07-29T16:12:31.322900Z

Having an alias that treats the uberjar as a :local/root dependency and runs the expected -main function inside it, so you get easy access to the t.d.a. / Clojure CLI infrastructure

seancorfield 2020-07-29T16:19:43.323400Z

This:

:aliases
 {:run       {:deps {worldsingles/worldsingles {:local/root "../../build/uberjars/worldsingles-1.0.0.jar"}}
              :fn worldsingles.publisher/-main}}
  ...
And then clojure -X:run

seancorfield 2020-07-29T16:20:38.324200Z

So you get the "benefit" of an AOT'd uberjar with the benefits of the Clojure CLI. And the program can read the basis ๐Ÿ™‚

seancorfield 2020-07-29T16:23:51.326Z

(of course, now you need the Clojure CLI installed on a target server, not just the JVM, and you need a deps.edn file in the folder where you start the app)

vlaaad 2020-07-29T16:35:15.326300Z

And internet access

vlaaad 2020-07-29T16:35:25.326400Z

And credentials for private repos

seancorfield 2020-07-29T16:37:32.327200Z

@vlaaad Not if the entire :deps is just the uberjar, right?

seancorfield 2020-07-29T16:37:55.327500Z

There are no other deps to fetch at that point.

alexmiller 2020-07-29T16:40:39.328200Z

It shouldnโ€™t be?

vlaaad 2020-07-29T16:40:39.328400Z

Ah, sorry, misread the situation

vlaaad 2020-07-29T16:41:05.328500Z

I was thinking about using clj without uberjar

seancorfield 2020-07-29T16:42:41.329800Z

Right, which we used to do on production (and, on one server, for "reasons" we still do that).

alexmiller 2020-07-29T16:43:25.330200Z

So Iโ€™m curious why you said that

seancorfield 2020-07-29T16:43:33.330400Z

I just did brew upgrade clojure on WSL1 on my Windows laptop last night and it updated me to 590. Hence my surprise.

seancorfield 2020-07-29T16:43:42.330800Z

Note: brew on Linux.

alexmiller 2020-07-29T16:43:53.331300Z

Thatโ€™s homebrew core, which I no longer update

alexmiller 2020-07-29T16:44:38.332Z

clojure/tools/clojure is official

seancorfield 2020-07-29T16:44:53.332200Z

I know. Hence my surprise ๐Ÿ™‚

alexmiller 2020-07-29T16:48:12.333Z

Well I released 590 a week ago, just took me a while to doc and announce

alexmiller 2020-07-29T16:48:24.333500Z

But I guess somebody updated it

borkdude 2020-07-29T18:31:49.334700Z

Not that I really care, just wanted to report that if you call a private function with -X, it also works:

borkdude@MBP2019 /tmp $ cat src/foo.clj
(ns foo)

(defn- foo [_]
  (prn :foo))

borkdude@MBP2019 /tmp $ cat deps.edn
{:aliases {:foo {:fn foo/foo}}}
borkdude@MBP2019 /tmp $ clojure -X:foo
:foo

๐Ÿ˜Ž 1
borkdude 2020-07-31T21:09:31.015600Z

The private var call still works with 619 ๐Ÿ™‚

alexmiller 2020-07-31T21:16:09.018400Z

I'm ok with that

alexmiller 2020-07-31T21:16:22.018600Z

I don't consider it a bug

alexmiller 2020-07-31T21:16:37.018800Z

private functions are only in your mind

borkdude 2020-07-31T21:17:26.019Z

I'm going to quote you on that when somebody will ask questions about this ๐Ÿ˜‚

$ bb '(ns foo) (defn- foo [] :foo!) (ns bar (:require foo)) (foo/foo)'
:foo!

2020-07-29T18:40:40.335800Z

ANybody else having issues with the recent tools-deps docker?

2020-07-29T18:42:12.336500Z

Specifically

Caused by: Syntax error compiling . at (aleph/http/core.clj:251:3).
Caused by: java.lang.IllegalArgumentException: No matching method setTransferEncodingChunked found taking 2 args for class io.netty.handler.codec.http.HttpUtil

2020-07-29T18:42:35.337Z

(I'm making assumptions here because nothing else has changed)

alexmiller 2020-07-29T18:44:06.337900Z

that's not intentional but interesting :)

alexmiller 2020-07-29T18:44:21.338400Z

it does make sense given the impl

seancorfield 2020-07-29T18:44:39.338900Z

@p14n change in JDK version perhaps? Last night I was helping some beginners debugging a weird reflection-based problem that changed between JDK 11 and JDK 14 (it was broken on 8 and 11 but worked on 14).

seancorfield 2020-07-29T18:46:11.339600Z

Because requiring-resolve can get at private Vars and there's no access check on that dynamic call path, right?

2020-07-29T18:46:24.340Z

That's what I thought. I switched to openjdk-8-tools-deps (tools-deps now 11) but no dice yet

alexmiller 2020-07-29T18:48:56.340300Z

right, just like calling through a var

2020-07-29T19:12:48.343400Z

Fixed by using clojure:openjdk-8-tools-deps-1.10.1.502 ๐Ÿคท

seancorfield 2020-07-29T19:13:32.344Z

A change in the default Clojure version perhaps, with stricter syntax checking?

ghadi 2020-07-29T19:14:52.344600Z

i don't use any of the clojure:* images

ghadi 2020-07-29T19:15:09.345400Z

they are not made by clojure team, and are not necessary IMHO

cap10morgan 2020-07-29T19:15:27.346Z

How is the groupId derived in clojure -Spom? mine keeps getting reset to the artifactId when I run it.

ghadi 2020-07-29T19:15:46.346200Z

I use an adoptopenjdk image and then add the clojure installer

seancorfield 2020-07-29T19:16:33.346600Z

That's a bug. That should not happen.

seancorfield 2020-07-29T19:16:42.346900Z

(and it's a new bug ^ @alexmiller)

cap10morgan 2020-07-29T19:17:27.347400Z

ah, interesting. this is with 1.10.1.590.

alexmiller 2020-07-29T19:17:33.347500Z

I don't think anything has changed there

seancorfield 2020-07-29T19:17:49.347600Z

(! 1133)-&gt; head pom.xml 
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;project xmlns="<http://maven.apache.org/POM/4.0.0>" xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>" xsi:schemaLocation="<http://maven.apache.org/POM/4.0.0> <http://maven.apache.org/xsd/maven-4.0.0.xsd>"&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;groupId&gt;seancorfield&lt;/groupId&gt;
  &lt;artifactId&gt;next.jdbc&lt;/artifactId&gt;
  &lt;version&gt;1.1.569&lt;/version&gt;
  &lt;name&gt;next.jdbc&lt;/name&gt;
  &lt;description&gt;The next generation of clojure.java.jdbc: a new low-level Clojure wrapper for JDBC-based access to databases.&lt;/description&gt;
  &lt;url&gt;<https://github.com/seancorfield/next-jdbc>&lt;/url&gt;
  &lt;licenses&gt;

Wed Jul 29 12:17:19
(sean)-(jobs:0)-(/Developer/workspace/next.jdbc)
(! 1134)-&gt; clojure -Spom

Wed Jul 29 12:17:30
(sean)-(jobs:0)-(/Developer/workspace/next.jdbc)
(! 1135)-&gt; git diff
diff --git a/pom.xml b/pom.xml
index 3dce875..5632254 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,7 +1,7 @@
 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
 &lt;project xmlns="<http://maven.apache.org/POM/4.0.0>" xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>" xsi:schemaLocation="<http://maven.apache.org/POM/4.0.0> <http://maven.apache.org/xsd/maven-4.0.0.xsd>"&gt;
   &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
-  &lt;groupId&gt;seancorfield&lt;/groupId&gt;
+  &lt;groupId&gt;next.jdbc&lt;/groupId&gt;
   &lt;artifactId&gt;next.jdbc&lt;/artifactId&gt;
   &lt;version&gt;1.1.569&lt;/version&gt;
   &lt;name&gt;next.jdbc&lt;/name&gt;

alexmiller 2020-07-29T19:17:58.347900Z

well, nothing intentional :)

๐Ÿ˜ 1
seancorfield 2020-07-29T19:18:14.348Z

The only change it makes is to overwrite the groupId

2020-07-29T19:19:12.348300Z

Do you host your own?

alexmiller 2020-07-29T19:21:27.348900Z

can you file a jira, I'm juggling many conversations right now

cap10morgan 2020-07-29T19:22:44.349100Z

Will do

cap10morgan 2020-07-29T19:25:30.350100Z

@seancorfield The expected behavior was just that it should leave that value alone when the pom.xml already exists?

cap10morgan 2020-07-29T19:28:59.350400Z

Hopefully that captures it: https://clojure.atlassian.net/browse/TDEPS-157

souenzzo 2020-07-29T19:31:02.351500Z

The function that turns (merge-cli-ops {:default :opts} "[:extra :opts]" "true") =&gt; {:extra {:opts true} :default :opts} is public?

seancorfield 2020-07-29T19:39:03.352Z

@cap10morgan Yup, it should only touch the dependencies in an existing pom.xml file.

๐Ÿ‘ 1
alexmiller 2020-07-29T19:42:45.352300Z

sorry, I don't understand the question

alexmiller 2020-07-29T19:43:20.352800Z

well, it's broader than that - deps, repos, directories

alexmiller 2020-07-29T19:44:00.353400Z

there has been some work done internally here to make this more configurable and that will eventually make its way into user configurability

1
alexmiller 2020-07-29T19:46:09.353500Z

or how it relates to tools.deps

souenzzo 2020-07-29T19:50:38.354200Z

I think that is this one https://github.com/clojure/brew-install/blob/1.10.1/src/main/resources/clj_exec.clj#L59

souenzzo 2020-07-29T19:51:19.354500Z

I liked the "DSL" to "assoc-in" values.

alexmiller 2020-07-29T20:47:02.355800Z

Oh, yes thatโ€™s it. Treat anything about this code as implementation detail though

alexmiller 2020-07-29T20:47:27.356300Z

It may migrate into Clojure itself

๐Ÿ‘ 1