Fork me on GitHub

Are there public docker images containing tools-build stuff somewhere?


I use this for building my containers:


- name: Setup Clojure
        uses: DeLaGuardo/setup-clojure@master
          tools-deps: 'latest'


(on github actions in that use case)


My issue is that I am building an uberjar in a CI pipeline I have no control over, and where the build machine has limited diskspace. Using uberdeps was too much. Trying with tools-build instead, and adding the deps {io.github.clojure/ {:git/tag "v0.7.5" :git/sha "34727f7"}} also downloads a lot of stuff. So I was thinking maybe there's a public docker image I could use instead, and I could then use whatever version of tools-build that it has pre-installed.


I'm using clojure:openjdk-18-tools-deps btw.


What's the most important problem for the Clojure programming language to tackle over the next 1-5 years? Curious both about what the actual dev team considers important, and what the broader community wants. What's not as good as it can be? How could it be improved?

💯 1

Adoption? Take a look at clojurians slack all-time stats — — Clojure ecosystem didn’t grow at all during the last 5 years

😨 2

Perhaps consolidation, for various problems there's always N solutions which while has its perks, in the end fragments the community IMO, it's a bit wasteful particularly considering community size


> Adoption If adoption is the goal -- I'd still ask what we want to do in order to cause adoption. Better CLI tooling with less friction? Better resources for getting started? In general, making Clojure Good would enable Adoption. There's room for more precision in that statement!

Alex Miller (Clojure team)13:02:06

The best way to increase adoption is to talk more about Clojure and why you like it / it solves problems to people that don't use Clojure

💯 1

@U064X3EF3 that makes sense, the community can help with that. But is that what the core team aims at? What's most important to you? What would you like to change?


@U45T93RA6 got any specific examples in mind? Like HTML routers? In general, I find the Clojure ecosystem to be less fragmented than other communities.


Exploratory re-hosting on post-Java platforms!


My impression is that it is more fragmented than Ruby, Elixir and C# community, for example. Maybe JavaScript too if you adjust for size, but less sure about that one.

Alex Miller (Clojure team)17:02:07

I don't think it's possible to intentionally change where an ecosystem is in the consolidation / choice availability continuum without substantial time and energy (and few people are likely to agree on the ideal endpoint), so that's not actually a useful thing to work on wrt adoption imo

Zach Mitchell, PhD17:02:37

Talking/marketing is definitely important. I've been doing software of some sort for almost 10 years and straight up hadn't heard of Clojure until about 6 months ago.

Alex Miller (Clojure team)17:02:37

From a core team perspective, we don't really think there are big things that need to be added to the language. There are a bunch of things we think are interesting and can be made better, but they are mostly probably less important than things have been done in the past.

👍 2

The main thing I'd like to see "improved" in the language is the dynamic addition of dependencies to a running REPL. There are JIRA tickets around that and we have an experimental branch of t.d.a. so it just needs polishing and "finishing" I think?

👍 2

And I guess Spec 2, once the defn integration design is finalized?


Otherwise, I'm very happy with the language and ecosystem. Well, even without those two, I'm very happy 🙂 Most Clojure developers seem very happy and tend to want more developers to join us, using Clojure, and try to "convert" other developers...?

Alex Miller (Clojure team)17:02:44

Increasing adoption and use is of course of interest. Adoption is a funnel. There are many points to apply pressure along the funnel. On the outer edge - telling good stories about Clojure to non-Clojurists is important to feed the outer part of the funnel. We've seen points in the past where we successfully connected to particular communities (Java is the most consistent, somewhat reduced by Java's language moves towards FP, Ruby/Python for dynamic/OO -> dynamic/FP/concurrency/perf, JS for a sane and fast feedback path to web dev, C++ for concurrency on a stable platform with less ceremony). We collectively in the Clojure bubble mostly talk to each other right now. Once people come in the door, the next question is how easy it is to learn and build something of use. There is always more to do on this. And then how do you really build systems at scale (both size and time). There is not one answer here - it is working on all parts of that.

💯 1

I've actually begun to focus more on driving adoption. My current main effort there is my job board (hoping it will also serve as a marketing tool for Clojure As A Career Option.) I'm cooking up some other initiatives with other folks. Feel like I haven't been that publicly active, but I've lately become obsessed with figuring out new ways to bring in more develoeprs


For example- I have a blog post draft on the surprising long-term benefits of learning Clojure + companies that will train you to write Clojure. Hoping to publish that in the next couple weeks, if anyone has their own long-term benefit stories they want to share, or if their company is hiring & training, would love to hear about it


re: how easy it is to learn and build something of use, I'm hoping to release some tools that help in that regard, too, but I don't like to talk about that too much without actually having something tangible to show


main thing I'm trying to say is this is something I care about, and I've been making many intentional moves to support adoption and enjoy talking about this stuff

❤️ 3
Alex Miller (Clojure team)17:02:07

and we thank you for it! :)


heh thanks - the reason I'm sharing is that I would enjoy talking more about this stuff with anyone interested, not to say "hey I'm doing these things!"


> From a core team perspective, we don't really think there are big things that need to be added to the language. There are a bunch of things we think are interesting and can be made better, but they are mostly probably less important than things have been done in the past. Really curious about the bunch of things you think are interesting 🙂


I think better user interfaces - both from the standpoint of finished applications and from the standpoint of programs and developer tooling - are one area where I think Clojure could grow a lot from where it is now. There's interesting work happening on both fronts - skija, reveal, portal, membrane, etc - but it hasn't consolidated into a standard "how to UI with Clojure" approach yet.

❤️ 4
Alex Miller (Clojure team)17:02:29

> Really curious about the bunch of things you think are interesting there is a group of interop things that we have been poking at and will continue to do so in 1.12 I suspect - static methods as fns, varargs, streams, better Path integration. sean mentioned the dynamic stuff which is something we been circling for a long time.

👍 2
Alex Miller (Clojure team)17:02:09

those are probably high on the list, there's no end of other ideas of course


> static methods as fns, varargs, streams, better Path integration. sean mentioned the dynamic stuff which is something we been circling for a long time. So less required java internal knowledge in order to get started? That would be really great. I haven't done a lot of java (I prefer Clojure) and I think I remember learning that you have to wrap static methods somehow.


> There's interesting work happening on both fronts Is it just me or does it seem like there's been an explosion of interesting stuff happening over the last few years? XTDB and pathom come to mind


oh also the whole @U04V15CAJ phenomenon

❤️ 2

Either a fantastic fortune or black magic, or some combination, no idea.


> Is it just me or does it seem like there's been an explosion of interesting stuff happening over the last few years? XTDB and pathom come to mind I have this impression that either we're picking up some Lisp inheritance -- or Clojure is actually continuing the tradition. I kind of expect some old Common Lisper to have used data explorers (#portal and friends) a whole lifetime. But the immutability perspective seems new to me. But it's really hard to separate rediscovering old ideas from creating new ones. And we should really be doing both.


I work on desktop, console and mobile apps in the games industry. I would love to be able to use Clojure for actual applications (video games) in that space instead of just for my own custom tools I use when developing. There is the Defold engine editor, but that is a dev tool, not an actual game. What prevents this from happening is mostly the JVM and the fact that it simply does not run on iOS or game consoles. People think we use C++ for performance which is true to an extent but actually the biggest reason is that it works on all platforms and is the main language of popular engines. Clojure would be fast enough for many games on modern machines if you just take a little care with memory use. So I would love to see Clojure hosted on other "platforms" than the JVM that are more portable, perhaps some LLVM backend? Seems most people in the Clojure community are server folks though, where the JVM is excellent. So maybe this would not help adoption much. I would love it though :)

👀 3
👍 1

@U89UL6P9P how do you envision Clojure's liveness / REPL / dynamism / incrementalism would work with LLVM? Is there an "LLVM server" running in dev? Or is there some JVM stuff, and an "LLVM emitter"? (I know nothing of LLVM other than that by being a backend the Rust compiler it gives nice speedups and nice cross platform capability)


I'd also love to hear if @U04V15CAJ has an opinion on how "Clojure and LLVM" could work. (I might be digging up old dirt here, if this has been discussed to death already)


Also, @U89UL6P9P, could GraalVM work? Why would LLVM be better suited for your case than Graal?


Maybe it makes more sense to approach it from the JVM + native interop direction, like #coffi is doing. @U5NCUG8NR mentioned in a podcast that one of this targets with that is writing games. I've never really looked at LLVM, so I'm not the person that can give a very informative answer on this.

👍 1

The JVM and maybe more specifically GraalVM Polyglot can target so many things now (it can also run LLVM) that it might not make a lot of sense to even leave the JVM for server/desktop programs in the future, maybe?


@U89UL6P9P I'm not in a game industry, so it might not make sense what I'm saying, but it might be interesting to look at JDK 17 + #coffi (or direct manual interop) and/or GraalVM LLVM support

👍 1

@U04V15CAJ The JVM is a non starter for anything but desktop games so any integration is off the table. Even if you are targeting Android you will typically do iOS also since that market is bigger so you will default to C++ for Android too, or Unity, which transpiles C# to C++. And for consoles, they have proprietary APIs and custom versions of operating systems that you can't just drop a JVM on top of without adapting the JVM itself for that environment first, so that is a huge task that is not worth the effort when you can just use the industry standard stuff already. For all platforms to be nicely accessible Clojure would have to be able to compile down to native COFF/PE/ELF executables without external dependencies besides whatever is the standard on each platform and have really good C and C++ interop for working with standard libraries. I know about GraalVM Native but that is not very mature yet, depends on external libraries you have to ship along with your built program and also targets only desktop, so it is actually worse than just bundling a JVM in every aspect except download size. GraalVM Native has fast startup which is good for command line utils but startup time is not super important with games because people tend to have them running for a while so other stuff, like peak performance matters more. @U3X7174KS LLVM is just a compiler backend. It has VM in the name but that is just because they have a made up instruction set for a "virtual machine" that they compile down to machine code for each specific machine they target. So you have to build a compiler frontend from scratch and hook it up to LLVM. LLVM is usable as a library from Java/Clojure so you can write the compiler in Clojure, much like the Clojurescript compiler. Any garbage collector would also need to be supplied externally. But I don't think Clojure actually needs a sophisticated GC. Non-cyclic structures like the ones used in the Clojure data types can be collected with reference counting. I think the hard part is how to allow users of that Clojure platform to access features of C and C++ that are needed for performance and interop, like allocating structures on the stack and inlining structures in each other and such. Since every compound type instance is a reference (pointer) by default on the JVM the Clojure language has no facilities to make that distinction in it's current syntax. Maybe it could be handled like on the CLR where you make the allocation strategy part of the type system (their struct/class distinction). That avoids having to have new syntax at the place where you use types. I have thought about this on and off since 2007 😄 but I don't have the time or energy to start or maintain a project like this. So I just keep wishing someone else will share this dream and pick it up...

🔥 2
❤️ 2
💯 2

Regarding interactive development workflow. That is totally possible by using LLVM as a library from a Clojure REPL session. LLVM can compile and run native code on the fly and replace existing compiled functions too, so you can get the same workflow as with JVM based Clojure. And then you can do an AOT compile down to a native executable for release.

💯 1

> • I know about GraalVM Native but that is not very mature yet > • depends on external libraries you have to ship along with your built program > • and also targets only desktop Those things aren't actually true (anymore). GraalVM is pretty mature now. You can build static binaries with it (at least on linux, on macOS it tends to depend on libz and some other libs that are always there on macOS/iOS). It also targets mobile. @U7RJTCH6J and I have done an episode about this on Apropos Podcast where we (mostly @U7RJTCH6J) built a backend in JVM Clojure, compiled that to a Graal binary which is hooked up with an iOS front-end built with XCode. The development experience might not be as smooth as doing everything with XCode, but at least you get to re-use JVM Clojure stuff directly, even on an iPhone.


But for a well-integrated mobile experience, I agree it's not as smooth as say doing everything in popular mobile-tech-du-jour. :)


Perhaps ClojureDart will help a lot here.


Thanks for the show link, @U04V15CAJ, looking forward to listening. 🙌


I'd love to see #cljtogether funding for research on this topic


What Adrian made is pretty cool. Maybe he can release a new beta so you can try it with testflight. You can make games on your iphone in Clojure basically, with a pre-defined API to control the UI. Just watch the stream to get an idea.


@U04V15CAJ that sounds really cool. Thanks for updating me on the GraalVM progress. I will check out the podcast :) How is the debugging experience though? If I compile directly to machine code with LLVM I can use standard platform debuggers. What GraalVM produces seems rather “opaque”.


I recommend asking in the graalvm community slack about this


The podcast approach: you could just develop your backend component on the JVM. After that, you compile it as a library and then hook up the mobile parts to it.

Joshua Suskalo15:02:25

Clojure on LLVM is totally feasible, and with #coffi we can actually wrap the libraries it provides for code generation etc directly from JVM clojure. So I think it's a feasible goal for somebody to write a version of Clojure that compiles to LLVM IR the same way that CLJS compiles to JS. That said it'd have the same kind of limitation of "no evaluation" and needing a JVM to do a repl. OFC we could also just implement CLJ from the ground up on LLVM, but at that stage I actually don't think I'd make Clojure, I'd make something closer to because it has transducers and protocols at the bottom instead of weird interop bits. OFC that also removes most of the library interoperability and just gets you back to square one on adoption, but I think that's just a natural outcome of trying to have a "native clojure" seeing as a massive portion of the library ecosystem depends on JVM features because the JVM is not an implementation detail, it's a feature.

Joshua Suskalo15:02:28

If you want to have Clojure work on other platforms that have access to the CLR, ClojureCLR is still a thing and could be relevant for you.

Joshua Suskalo15:02:00

Oh also @U89UL6P9P I know this doesn't solve the "JVM doesn't target my targets" problem, but download size of the JVM is no longer really an issue if you put a little effort into your build step. A minimal JVM that can run Clojure is ~40 MB when packaged with jlink and jpackage.

Joshua Suskalo15:02:50

Additionally stuff like Project Valhalla which enables value types which are passed on the stack landing in the future would help with having more control over your performance and being less at the whims of the JIT


Thanks for the tips. I know about that stuff already though. It's great, but as you said, does not solve the main issue.

Joshua Suskalo16:02:44

Yeah, makes sense. For my personal usecase I'm alright with targeting just desktop since my primary release platform would be Steam, but I know that's less than ideal. One thing you could look into is the arcadia project which uses Clojure CLR on some industrial-strength game engines like Unity and Godot.


@U89UL6P9P it occurs to me that you might be interested in Clasp, a variant of Common Lisp that tries to improve the interop story with C++:


@U89UL6P9P, I saw you pop up on the graalvm community slack. For clojure specific usage, check out #graalvm and #graalvm-mobile. Native image works great for desktop and mobile. provides excellent ffi support. I've built a proof of concept that runs on iOS. The same idea could be applied to android. I don't think there are any technical limitations. It's mostly just a matter of hooking up the various pieces.


Wow, thanks for all the great tips!


In my log, I see an error is logged, but no stacktrace is printed:


How come the stacktrace is stripped?


Also, here's a recent blog post on this subject:

👍 1

Thanks guys!


Actually I just remembered I saw this poll weeks ago:


happy to help 🙂

💯 1

(defn fix
  (fn [x]
    (f (fix f) x)))

(defn ff
  [f node]
  (if-let [x (:a node)]
    {:b (f x)}

(defn gg
  [f node]
  (if-let [x (:b node)]
    {:c (f x)}

(ff identity {:a {:a :end}})
;; {:b {:a :end}}

((fix ff) {:a {:a :end}})
;; {:b {:b :end}}

(gg identity ((fix ff) {:a {:a :end}}))
;; {:c {:b :end}}

((fix gg) ((fix ff) {:a {:a :end}}))
;; {:c {:c :end}}

(defn compose
  [f g]
    "stuff here?"))

((compose ff gg) identity {:a {:a :end}})
;; {:c {:a :end}} ;; this is what I expect but dunno how to get

((fix (compose ff gg)) {:a {:a :end}})
;; {:c {:c :end}} ;; this is what I expect but dunno how to get
Hey, how can I compose ff and gg into one function? Thanks!


Oh, I think its’ not possible as long as I’m returning {:b (f x)} in ff since then gg will never see it…


At least, that’s what I was thinking when I made

(defn compose
  [f g]
    [fg x]
    (f (partial g fg) x)))
but now I’m not sure


I'm not sure what your goal is here. I don't understand what the abstraction is supposed to be, let alone what its value is. is compose supposed to be like comp but with an extra argument?


I’m trying to transform an ast and I ended up with a pattern where I’m passing in the function to apply to the child node. I can call (f identity node) and it’ll only apply once. That makes it easier for me to debug. Then I figured out how to make it recursive with fix which is a headtrip. Now I can make one function that transforms the whole tree. Now I have two functions that transform the whole tree. The output of one is the input to the other. I could walk the whole tree twice and have the answer that I want. I’m trying to compose the functions somehow so that a single node gets transformed twice before the recursion moves on to the child node…


I think I’d know how if I understood recursion schemes but I don’t…


Ok so is ((compose ff gg) identity {:a {:a :end}}) equivalent to (ff identity (gg identity {:a {:a :end}})) ?


That’s my intent, yes.


Thanks for taking time out of your day for this.


So this is definitely possible with comp and partial:

((apply comp (map #(partial % identity) [gg ff])) {:a {:a :end}})


I think I have something working.

(defn compose
  [f g]
    [fg x]
    (g fg (f identity x))))
Let me read what you put…


As a function:

(defn compose
    [fg x]
    ((apply comp (map #(partial % fg) fns)) x)))
I tried to make it more generic in case there are more than two functions but it might be too complicated in your case


Oh, I see. Ok, that part went over my head and I was wondering why you wrote it like that.


FYI your solution doesn't work for this example: ((fix (compose gg ff)) {:a {:a :end}}) it gives {:b {:b :end}}


Huh. It seems to work for me… Maybe I need to restart my repl. I have

((compose ff gg) identity {:a {:a :end}})
;; {:c {:a :end}}

((fix (compose ff gg)) {:a {:a :end}})
;; {:c {:c :end}}


nevermind, you're right, it works, I just had the composing functions the other way


Ah, ok. Thanks for the help!


I'm trying to use VisualVm to set up a sampling profiler for an application, however when start the CPU sampler it changes to status "refreshing" and does nothing else. I've tried searching the official docs but they don't have anything to say about the Sampler that I can see, and definitely no docs on possible Sampler statuses. Anybody seen this before?