Fork me on GitHub
#clojure
<
2021-09-28
>
dgb2309:09:04

never heard of this. However it is more common to do it the other way around, execute JS/CLJS from the JVM via Nashorn.

Nazral11:09:15

@U01EFUL1A8M thanks for the recommendation, it's to call some java from an electron app, do you know if it is possible via Nashorn? Also Nashorn seems to have been deprecated in favor of GraalJS

dgb2312:09:11

@UGH9KH1DF Sorry I cannot help you there!

didibus18:09:29

Not sure how that works but I see no reason it wouldn't work with Clojure too, being that Clojure is just Java

didibus18:09:04

Though might either need to AOT compile the Clojure, or use the Clojure Java APIs maybe

Nazral08:09:12

@U0K064KQV I managed to make it work it was pretty straightforward in the end, and indeed it needs AOT compile

👍 1
danielneal10:09:26

@cgrand not sure where you’re at with it, but I’d be interested in trying out clojure dart + flutter. If I sign up as a supporter is there some kinda early beta access option.

bortexz15:09:30

Trying out the performance of merge operations, I discovered that when a small map (array-map?) goes first and then a large map (hash-map?) the operation goes quite slow:

(c/quick-bench (merge {:a 1 :b 6} 
                      {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 8 :o 9 :l 10 :v 11}))

Evaluation count : 614460 in 6 samples of 102410 calls.
             Execution time mean : 974.772023 ns
    Execution time std-deviation : 2.971197 ns
   Execution time lower quantile : 970.592882 ns ( 2.5%)
   Execution time upper quantile : 977.600861 ns (97.5%)
                   Overhead used : 2.144573 ns
while if you put the large map first, then it goes much faster
(c/quick-bench (merge {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 8 :o 9 :l 10 :v 11} 
                      {:a 1 :b 6}))

Evaluation count : 4681524 in 6 samples of 780254 calls.
             Execution time mean : 138.013267 ns
    Execution time std-deviation : 15.762978 ns
   Execution time lower quantile : 126.502904 ns ( 2.5%)
   Execution time upper quantile : 159.704613 ns (97.5%)
                   Overhead used : 2.144573 ns
is there anything that can be done to avoid this difference without having to worry on the order of the maps?

Ben Sless15:09:56

If you care about performance, don't use merge* • terms and conditions may apply

Ben Sless15:09:48

generally, something like (persistent! (reduce-kv assoc! (transient to) from) is faster

Ben Sless15:09:18

you can also try without the transient, i.e. (reduce-kv assoc to from)

bortexz15:09:06

thanks @UK0810AQ2 , even those solutions suffer from the same problem even going slightly faster. I could do to try and make use of the hash-map first if it’s there sometimes:

(defn merge*
    [m1 m2]
    (if (> (count m1) (count m2))
      (reduce-kv assoc m1 m2)
      (reduce-kv assoc m2 m1)))
but anyway it looks like at the point where array-maps need to become hash-maps, the performance penalty it will be there. I guess that’s what I am looking after, a way to avoid such specific penalty, but might be that there’s no way around it

vemv15:09:26

it might not be out of the question to avoid map literals and use the related constructors directly? then you can sprinkle specs for ensuring your perf expectations will hold

bortexz15:09:36

You mean using (hash-map) ? Have tried, doesn’t help

(c/quick-bench (merge (hash-map :a 1 :b 6) {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 8 :o 9 :l 10 :v 11})

Evaluation count : 513588 in 6 samples of 85598 calls.
             Execution time mean : 1.168965 µs
    Execution time std-deviation : 7.250814 ns
   Execution time lower quantile : 1.161225 µs ( 2.5%)
   Execution time upper quantile : 1.178713 µs (97.5%)
                   Overhead used : 2.144573 ns

👍 1
bortexz15:09:02

I think I will just be careful with merge and try not to abuse it, maybe have a bit more verbose code sometimes and use map literals

Ben Sless15:09:34

Your solution based on count is unfortunately incorrect when keys overlap 😞

👍 1
Ben Sless15:09:03

If you know all the keys in advance and the merge is of literal maps unroll it to a series of assoc-s

Ben Sless15:09:27

also, is your repl started with lein?

bortexz15:09:46

True, it will fail on overlapping keys. No, I use Calva with deps.edn.

Ben Sless15:09:22

Just to make sure

bortexz15:09:23

The assoc-s have the same problem, 1 assoc takes 60ns but at the moment where the map is 8 keys length, the next assoc takes 500ns

Ben Sless15:09:30

(import '(java.lang.management ManagementFactory RuntimeMXBean))

Ben Sless15:09:50

(into [] (.getInputArguments (ManagementFactory/getRuntimeMXBean)))

bortexz15:09:07

["-Dclojure.basis=.cpcache/881021756.basis"]

Ben Sless15:09:18

alright, you're running with full JIT

Ben Sless15:09:45

> the next assoc takes ~500ns That's because you're growing from an ArrayMap to a HashMap

1
Ben Sless15:09:13

You can unroll everything into assoc! into a transient empty hash map

Ben Sless15:09:19

and make sure it's a hash map to begin with

bortexz15:09:20

yeah that seems to be the problem in all cases, that moment when it needs to grow

Ben Sless15:09:39

If you start off with a hash map you won't pay that cost

Ben Sless16:09:00

but you might get worse performance for small maps as a result of the merge

bortexz16:09:08

> alright, you’re running with full JIT is this good or bad for performance testing? Not very familiar with those bits

Ben Sless16:09:18

Not only good, mandatory

bortexz16:09:44

unfortunately (hash-map) returns {} which is a persistenArrayMap. Any way to create an empty hash-map? directly from the class?

Ben Sless16:09:57

Yes, writing an example now

Ben Sless16:09:49

Try this

(defn merge2 [m1 m2] (persistent! (reduce-kv assoc! (reduce-kv assoc! (transient clojure.lang.PersistentHashMap/EMPTY) m1) m2)))

Ben Sless16:09:09

The "problem" is that when growing from ArrayMap to HashMap you're basically running the inner form of this function. This implementation only iterates over each map once

Ben Sless16:09:56

I spent lots of time trying to optimize merge, I don't like any implementation I managed to come up with, yet

bortexz16:09:15

yeah, it improves the performance for that specific moment of growing, but seems to be worse overall

Ben Sless16:09:36

last bit of black magic

Ben Sless16:09:42

(defn -merge [m1 m2] (if (< 8 (+ (count m1) (count m2))) (merge2 m1 m2) (reduce-kv assoc m1 m2)))

Ben Sless16:09:56

Maybe with transient for the second case, too, not sure

bortexz16:09:20

(c/quick-bench (-merge {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 8 :o 9 :l 10 :v 11} {:a 1 :b 6}))

Evaluation count : 1381080 in 6 samples of 230180 calls.
             Execution time mean : 436.719037 ns
    Execution time std-deviation : 17.330955 ns
   Execution time lower quantile : 428.597133 ns ( 2.5%)
   Execution time upper quantile : 466.822495 ns (97.5%)
                   Overhead used : 2.144573 ns

bortexz16:09:26

This one runs much slower though

Ben Sless16:09:03

Yeah, it's the math, hang on I'll open a real editor

Ben Sless16:09:09

Need to decompile

bortexz16:09:24

It’s interesting because I would think that if the problem was the moment of transforming from array-map to hash-map, something like

(merge clojure.lang.PersistentHashMap/EMPTY m1 m2)
would solve it, but it has terrible performance 🙃

Ben Sless16:09:47

yuck

(defn merge-meh
  [m1 m2]
  (persistent!
   (reduce-kv
    assoc!
    (reduce-kv
     assoc!
     (transient clojure.lang.PersistentHashMap/EMPTY)
     m1)
    m2)))

(defn merge-ok
  [m1 m2]
  (persistent!
   (reduce-kv
    assoc!
    (transient m1)
    m2)))

(defn merge2
  [m1 m2]
  (let [c1 (count m1)]
    (if (> c1 8)
      (merge-ok m1 m2)
      (if (< 8 (unchecked-add c1 (count m2)))
        (merge-meh m1 m2)
        (merge-ok m1 m2)))))

Ben Sless16:09:44

but it's fast =\

bortexz16:09:58

that’s quite good, like 0.6 of the bad scenario and keeps the performance of the good scenario

Ben Sless16:09:26

And that's before doing any interop or any ugly tricks

👍 1
bortexz16:09:27

thanks @UK0810AQ2 it has been interesting 🙂 I think I will still be cautious when to use merge and probably keep using the core one, but I will keep this around just in case!

bortexz16:09:11

yeah…I wanted to avoid as much as possible ugly tricks or hacks, I’d rather be cautious on my uses of merge than abusing a hacky implementation

Ben Sless16:09:56

yeah it's easier to not use merge on a hot path

👀 1
bortexz17:09:08

Taking some inspiration from the faster fast-merge issue on clj-fast, this one covers the case where one of the other might already be persistent hash maps to use them as the “source” to merge into, still “slow” when merging two array-maps that become a hash-map, and it only accepts 2 maps

(defn rassoc! [^clojure.lang.ITransientAssociative acc k v]
    (if-not (acc k)
      (.assoc acc k v)
      acc))

  (defn lassoc! [^clojure.lang.ITransientAssociative acc k v]
    (.assoc acc k v))

  (defn rmerge!
    [l  r]
    (if (instance? clojure.lang.IKVReduce l)
      (.kvreduce ^clojure.lang.IKVReduce l  rassoc! r)
      (clojure.core.protocols/kv-reduce l  rassoc! r)))

  (defn lmerge!
    [l  r]
    (if (instance? clojure.lang.IKVReduce r)
      (.kvreduce ^clojure.lang.IKVReduce r  lassoc! l)
      (clojure.core.protocols/kv-reduce r  lassoc! l)))

  (defn merge! [m1 m2]
    (if (instance? clojure.lang.PersistentHashMap m1)
      (persistent! (lmerge! (transient m1) m2))
      (persistent! (rmerge! m1 (transient m2)))))

Ben Sless17:09:49

As you see, I've been at it for a while 😄

bortexz17:09:05

yes haha even if I could live with the performance penalty or be cautious about it, difficult to not enter the rabbit hole

bortexz17:09:27

will leave the above code in the issue in case someone finds it useful

Ben Sless17:09:33

re: the order of maps You shouldn't be surprised by big into small being slower than small into big. Why? You need to iterate over the map!

Ben Sless17:09:54

Iterating over 10 keys is slow than than iterating over 2 keys

bortexz17:09:25

that makes sense, yeah

Ben Sless17:09:32

We could do something clever, though

bortexz17:09:43

I’ll change my impl

bortexz17:09:50

instead of checking persistenthashmap

bortexz17:09:03

always use as source the bigger map

bortexz17:09:12

no matter the type

Ben Sless17:09:18

no, that brings you back to the problem of key collision

bortexz17:09:18

(defn merge! [m1 m2]
    (if (< (count m1) (count m2))
      (persistent! (rmerge! m1 (transient m2)))
      (persistent! (lmerge! (transient m1) m2))))

bortexz17:09:33

in combination with the rmerge! or lmerge! works fine

Ben Sless17:09:42

What we really need is an "update" method in the map which can handle collisions explicitly

Ben Sless17:09:58

how are lmerge and rmerge implemented?

bortexz17:09:14

(defn rassoc! [^clojure.lang.ITransientAssociative acc k v]
    (if-not (acc k)
      (.assoc acc k v)
      acc))

  (defn lassoc! [^clojure.lang.ITransientAssociative acc k v]
    (.assoc acc k v))

  (defn rmerge!
    [l  r]
    (if (instance? clojure.lang.IKVReduce l)
      (.kvreduce ^clojure.lang.IKVReduce l  rassoc! r)
      (clojure.core.protocols/kv-reduce l  rassoc! r)))

  (defn lmerge!
    [l  r]
    (if (instance? clojure.lang.IKVReduce r)
      (.kvreduce ^clojure.lang.IKVReduce r  lassoc! l)
      (clojure.core.protocols/kv-reduce r  lassoc! l)))

Ben Sless17:09:38

right, rassoc is what I wanted to avoid

Ben Sless17:09:46

I don't want to pay for lookup

Ben Sless17:09:51

no choice though

Ben Sless17:09:14

unless we get something like update

bortexz17:09:21

true, but update would always create the given key even if it didn’t existed

bortexz08:09:34

realised that is fine on rmerge, so either take right key or left key

souenzzo19:09:02

(into {} cat [m1 m2 m3 ...]) should be faster once it uses transient

Ben Sless20:09:01

@U2J4FRT2T try it with two maps with sizes 4 and 5 with no intersection 🙂

James Carr15:09:43

Are clojars published regularly? I heard someone mention that tools.build is only available via git and not any other repository

James Carr15:09:47

that doesn't feel right?

hiredman16:09:53

clojars is a community maven repo, it isn't published regularly, people publish maven artifacts(jar files) to it

hiredman16:09:55

the newer clj/clojure command line launchers that are built on tools deps can consume some dependencies directly from git without needing jars

James Carr16:09:20

so is that the recommended practice? Say you have a project with 12 or so dependencies... you just pull em directly from git vs. publishing to an artifact repository?

✔️ 1
👎 1
didibus18:09:59

I wouldn't say it's recommended. It's an option, recommendations don't exist yet I would say

didibus18:09:46

Personally, I'd recommend you publish your libraries to Maven Central

didibus18:09:01

That's the friendliest to legitimate professional and enterprise consumption

didibus18:09:31

Because people can now pull it from a Java or Scala project, and they can easily mirror maven central internally as well.

hiredman16:09:47

in general if you are consuming a library you are not publishing it, it is code someone else has written and they have make it available how they want (maven, git, etc) and you consume it from however they publish it

hiredman16:09:23

in general if you are building some kind of application, you consume dependencies but nothing depends on you, you are the root of the dependency graph

hiredman16:09:05

and whatever artifact you create is intended for being executed somewhere, not published to a repo (although some orgs do use maven repos for deployments)

hiredman16:09:43

so if you are building an app, it doesn't matter much, git or maven, as long as you are using something that understands git dependencies

hiredman16:09:24

if you are building a library it is a little more complicated because your dependencies become the transitive dependencies of anything that depends on you, and depending on who your audience is they may not be able to consume git deps, and some parts of the way git deps work (the coordinate is kind of assigned by the dependent, versions are shas) means there is more potential for mixups (depending on the same project with different coordinates, depending on the same project with shas that are not comparable, etc)

hiredman16:09:42

and maven repos have been in use for, I dunno, close to 20 years now? still plenty of foot guns, but very mature

hiredman16:09:17

(maven 1.x's repository docs start off trying to convince you not to store jars in CVS)

hiredman17:09:18

I very rarely (never?) stick with a pet project long enough for it to useful to others, but in general my pet projects are small, pure clojure, don't require aot compilation, and have minimal external dependencies (although sometimes the transitve dependency graph is large, core.async brings in a lot), which seem like the ideal characteristics for depending on something from git

seancorfield17:09:50

@james.r.carr In addition, with the newer features in the Clojure CLI, it is possible to consume (depend on) git projects that previously had to be prepared ("built") and deployed to Clojars because the CLI now supports the concept of a "prep" step for a git dependency -- such as compiling Java source to .class files, AOT compiling certain Clojure namespaces for :gen-class stuff etc.

seancorfield17:09:56

And all of the "tools" -- in the context of the CLI's -T option -- are generally intended to be installed from source (i.e., git deps).

seancorfield17:09:34

(feel free to ask more in-depth Qs about the CLI-related stuff in #tools-deps or the new build.clj stuff in #tools-build)

didibus18:09:31

I hope publishing exclusively to git doesn't become the norm. My suggestion is to publish your libraries to Maven Central and optionally also to git. Maven Central has a few benefits to users: 1. If you want to use a Clojure library from Java or Scala or Kotlin, either your library directly or a library that depends on your library, this will only work transparently if you've published your library to a Maven repo. 2. Lots of companies use internal mirrors of public repos, so that they are not at the mercy of a public repo going down or being slow, or being hijacked. Most of the time, Maven Central will already be mirrored and will be well supported by such mirroring tools like Artifactory. 3. It works with Lein and Boot and Gradle and Ant and everything else. That is, unless you want to become an island.

1
1
p-himik18:09:04

Correct me if I'm wrong, but: 1. Easily solved with Git submodules or subtrees or whatever you prefer 2. Caching proxies, if you really want to stick with the original URL. Your own local Git server otherwise 3. No idea about Boot, Gradle, and Ant, but Lein definitely has at least one plugin for working with Git dependencies

phronmophobic18:09:10

I'm not sure anything is "easily solved" with git submodules or subtrees 😛

3
phronmophobic19:09:35

I'm comfortable with git submodules, but I worked with plenty of teams that stumble over git submodules. Support for submodules has improved, but it does add complexity. tldr: I'm just poking fun at git

💯 2
phronmophobic19:09:56

> No idea about Boot, Gradle, and Ant, but Lein definitely has at least one plugin for working with Git dependencies Would any of these tools know how to "prep" a library downloaded from git? even if there is a plugin that supports git?

p-himik19:09:35

The plugins/tools could get up to speed, sure. Especially given that tools.build is made with the reuse in mind.

p-himik19:09:22

Or it could become a part of Java app's build process - again, by reusing tools.build.

phronmophobic19:09:55

That seems like a huge difference between an artifact on maven vs. trying to consume a git only library. Presumably, the artifact on maven would already work, out of the box, with all of these tools.

p-himik19:09:51

Difference - of course. Although making a Git dep work in a Java app would likely by itself be a reusable process, so it's not that huge. Definitely not enough to make Git deps an island.

Alex Miller (Clojure team)19:09:22

git deps is best, imo, for tools and utilities

Alex Miller (Clojure team)19:09:27

for libs, I think there is a lot of benefit to being available to a wider set of existing tools via Maven-located artifacts

👍 2
Alex Miller (Clojure team)19:09:35

git deps are also very useful to try things during dev - you can put a fix on a branch and have someone try a sha before you apply a fix in the main release (I do this all the time)

p-himik19:09:45

I've seen usages of Git deps for libraries in cases where some ad-hoc patching is needed or a version in Maven hasn't been updated. Seems like it's a similar argument to using e.g. Flatpak/AppImage/Snap vs using your OS's software distribution system. Both have pros and cons.

phronmophobic19:09:41

Right, I'm excited about the new features clojure's cli is getting. I've used git deps and local deps in situations that would have been awkward otherwise. Just trying to point out that there are trade-offs vs using something like clojars.

seancorfield19:09:27

All of the things we currently use as git deps at work are dev/test pipeline stuff. For anything that goes into our deployable artifacts, we use Maven/Clojars deps. That's more happenstance right now than by design but I figured I'd offer that as anecdata 🙂

James Carr20:09:47

Yeah I agree with that sentiment. Git deps for tools and active development, releases for libraries intended for use in production applications

didibus21:09:37

Glad everyone agrees that libs are better published in a Maven-repo. My preference for Maven Central is simply because it tends to be already setup for all JVM build tooling and mirroring systems. Assuming a company where Clojure is not the dominant language, but Java is, and the company has an internal Artifactory mirror, you'd need to convince leadership to add the Clojar repo as well to be mirrored. But this is much better already then git deps, where you'd ask leadership to build a whole custom mirroring facility just because you've decided you prefer Clojure over Java? Or because you'd like to use a Clojure lib from Java.

phronmophobic21:09:14

I didn't say maven was strictly better. There are tradeoffs. It's worth considering the intended audience for your project.

seancorfield21:09:34

> Glad everyone agrees that libs are better published in a Maven-repo. I don't agree -- and what I said was not agreement with your position: I was just noting that the production artifacts we build today do not rely on git deps. As I said, that's "more happenstance ... than by design". Our CI setup already has git available and does git-based operations (tagging etc) as well as the test/build tooling relying on git deps -- so it would not be problematic at all for our production artifacts to depend on such git deps.

Max23:09:30

To throw in my 2c, lein’s git plugin is a huge pain. It doesn’t handle transitive dependencies well, ssh key management is a frequent gotcha. At work we’re actively trying to stop using it. Just a little evidence that deploying libraries to maven repos is the most compatible option.

seancorfield23:09:43

@U01EB0V3H39 or switch to the CLI and deps.edn instead of lein? 🙂

Max23:09:13

Easier said than done! I was intending to directly respond to the title comment: > Lein definitely has at least one plugin for working with Git dependencies

seancorfield00:09:32

We switched from lein to boot nearly six years ago and then to deps.edn about three years ago. Very happy with that switch.

didibus06:09:03

What's the argument for Git, beyond just that the library author doesn't have to build and publish to Clojar or Maven Central? I mean specifically for library publishing, I agree with everything Alex said with regards to its usefulness at dev time and for tooling its fine as well.

p-himik07:09:49

Can use the most recent version of the code. Can use any branch. Can use your own changes added on top.

p-himik18:09:43

So I wouldn't say that a library that's distributed only via Git is truly an island.

hiredman18:09:54

git has a number of different transports

hiredman18:09:25

so "caching proxies" is a very complicated proposition

p-himik18:09:10

I see. But it would become complicated as soon as you need a library that's not available via HTTP. My experience is, of course, anecdotal, but I'm yet to see such a library. Even then, seems like there's insteadOf config: https://git-scm.com/docs/git-config#Documentation/git-config.txt-urlltbasegtinsteadOf Which practically replaces the need for proxies with an ability to use a local server, it seems.

phronmophobic19:09:56

> No idea about Boot, Gradle, and Ant, but Lein definitely has at least one plugin for working with Git dependencies Would any of these tools know how to "prep" a library downloaded from git? even if there is a plugin that supports git?

Kelvin21:09:41

At our company we actually moved away from publishing our libraries on Clojars and the like in favor of using Git SHAs. The advantages are obvious when these libraries are mainly internal - one can update deps very quickly without fiddling around with artifacts, version naming, etc.

didibus07:09:40

Agreed, if you're a Clojure only shop (as in no other JVM language is used), for your own internal use, its nice not to have to setup a separate shared internal Maven repo. I was talking more for the Clojure OSS.

didibus07:09:21

If the community starts to release libs to git only, it means no other JVM language can use Clojure libs transparently, and some companies won't be able to easily mirror the libs they depend on if they have a policy to do so (by easy I mean using off the shelf tools to do so like JFrog Artifactory or AWS CodeArtifact or Sonatype Nexus, etc.). That's why I hope the practice of publishing to Clojar or Maven Central will continue. Ideally, I'd like people to have git tags for git deps, and also publish to Maven Central or at least Clojars. If you release to Maven Central and Git, you get the best of all worlds, and people can pick n choose.

milt13:09:36

(also at @U02FU7RMG8M’s shop) I definitely spearheaded our headlong jump into git deps after becoming increasingly infuriated with the ongoing maintenance of our internal Nexus server and setting new devs up for signing. That said, automation makes it trivial to also deploy our versioned releases to something like Clojars or Maven Central and I agree it is probably best for the community at large to do so, the social choice.

milt13:09:44

With the recent addition of the checked tag + sha form of git deps though I will say that I feel solid sticking with git deps on our own projects.

Kelvin21:09:39

Of course, when it comes to publishing OSS Git-only and using Git-only OSS...yeah things might be different. At least for us we'll continue to do Git-only publishing due to the aforementioned advantages, and with the increasing support for Git tags we might be seeing a convergence towards the artifact model anyways.

Kelvin21:09:17

Even Rich himself argued that there are advantages of using Git over Maven/Clojars (or more specifically SHAs vs Semver) in this talk (at 48:47): https://youtu.be/oyLBGkS5ICk?t=2927

1
👍 1
Eddie23:09:52

I know I am swimming a little too far from shore here, but is there a way to globally set *compile-files* to true? I would like to do this outside of a binding. Perhaps via Java system properties at startup?

Eddie23:09:10

I tried .set on the static compiler attribute.

(.set Compiler/COMPILE_FILES true)
Execution error (IllegalStateException) at erp12.clark-example.play/eval2822 (form-init13317944995014988813.clj:1).
Can't change/establish root binding of: *compile-files* with set

ghadi23:09:31

what are you trying to achieve?

Eddie23:09:19

Probably nothing good. Just experimenting at the moment. I want to grab the class files for the in-memory classes so that I can package them in a jar and ship them off to a cluster. I explained a bit more background in the comments here. https://stackoverflow.com/questions/69356231/get-or-write-class-files-for-the-classes-in-the-dynamicclassloader

Eddie23:09:35

Looks like this works, but I’m not sure if there will be any negative consequences

(.bindRoot Compiler/COMPILE_FILES true)

hiredman23:09:41

just use reflection to pull them out of the dynamic classloaders classCache

Eddie23:09:35

That will give the Class objects right? I’m not sure how to get the bytecode from those.

hiredman23:09:08

ah, of course, I was misrembering

Eddie23:09:07

In my case, I am working with an Apache Spark cluster. It has a mechanism to accept jars (or individual class files) and distribute them amongst the workers without restarting the JVMs. For Scala folks, their REPLs write class files for each command and ships that to the cluster. I would like to emulate that.

hiredman23:09:31

it may be better to ship clojure source

Eddie23:09:59

I thought about that too, but I wasn’t sure how to ensure that the Clojure source doesn’t reference something that isn’t accessible on the workers. For example, a fn defined outside the source sent to the cluster.

hiredman23:09:35

if you are entirely talking about a repl, then everything is either something on the classpath (and gettable as a resource) or created by evaluating code in the repl, so just capture the code being read in at the repl

hiredman00:09:38

the type clojure uses for *in* by default at the repl got some features that can help capture that https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LineNumberingPushbackReader.java#L47-L59

Eddie00:09:48

Hmm… That’s an interesting idea. I need to solve this problem when running the application with clj or IDE or whatever as well but that still gives me something to think about.

hiredman00:09:03

There are tools people have written for aws lambdas that also might be good to look at

didibus07:09:21

If the community starts to release libs to git only, it means no other JVM language can use Clojure libs transparently, and some companies won't be able to easily mirror the libs they depend on if they have a policy to do so (by easy I mean using off the shelf tools to do so like JFrog Artifactory or AWS CodeArtifact or Sonatype Nexus, etc.). That's why I hope the practice of publishing to Clojar or Maven Central will continue. Ideally, I'd like people to have git tags for git deps, and also publish to Maven Central or at least Clojars. If you release to Maven Central and Git, you get the best of all worlds, and people can pick n choose.