Fork me on GitHub

why does it need to be replaced with reduce? seems to be working


if the return values of the builder methods matter


which, depend on the builder sometimes it matters, sometimes it doesn't


c.j.d. is very focused on beans. I'd have to do something else to work with builder classes. Still, I have the JIRA issue now 🙂

👍 4

Will this be me if I learn a LISP? Please be honest.


But seriously, I am looking for book suggestions.

Alex Miller (Clojure team)00:01:06

Only if you do it right! ;)


sicp is a lisp book, but it is using lisp to understand foundational computer science stuff, so it is great, but not really an intro to clojure kind of thing

Alex Miller (Clojure team)00:01:31

Learning Scheme/Lisp is a good side effect of reading SICP but not really the point :)

hiredman00:01:19 (links to the 1st edition of programming clojure, but the 3rd edition is current)

Alex Miller (Clojure team)00:01:40

If your goal is to learn Clojure, I’d recommend Clojure for the Brave and the True, Getting Clojure, Living Clojure, and Programming Clojure as good starters

Alper Cugun08:01:01

All four? I read Brave, what should I read next?


Hi everyone, I have a web application that downloads .jpg images and stores under /resource/public/img folder , everything works fine when running in dev, I want to deploy with a uberjar , but the images are not stored under /resource/public/img anymore, since is a .jar, it seems that the resource folder can't be updated?. I tried to wrap-resources to another folder, but it keeps serving from /resource/public/img , any idea on why is that?


a resource is optionally from inside a jar, or on disk


if you want the running app to store on disk, you probably don't want resources, but rather files


and you'd have a task at deploy or app startup to make sure the directory structure is ready for usage (and likely configure its location)


yeah I tried that, but it keeps serving the static files from /resource/public/ from the .jar

(defn wrap-base [handler]
  (-> ((:middleware defaults) handler)
        (-> site-defaults
            (assoc-in [:security :anti-forgery] false)
          (assoc-in [:static :resources] "/var/www/public/")
            (assoc-in  [:session :store] (ttl-memory-store (* 60 30)))))


you need wrap-files, it's not a default

metal 4


(assoc-in [:static :files] "/var/www/public/")
it worked, many thanks!

👍 4

oh, will try


Does Clojure have any good GUI toolkits? I was a bit disappointed with Erlang/Elixir’s offerings, even Joe Armstrong evaluated their options and found them severely lacking. But I expect there would be more options on a JVM language.


Interesting thanks


cljfx also looks good. There's a #cljfx channel for it.


Those are the two most popular ones I believe. You can also interop with the Java toolkits directly, those above two are wrappers for some of them. And some people go for ClojureScript for GUIs instead, building over Electron, etc.


I’m a little confused why the Clojure GUI toolkits don’t have websites with all the GUI elements layed out. I also went to the official JavaFX website and it’s hard to find screenshots of the GUI in action. Seems like a lost opportunity for adoption when it’s all so abstract.


I’ve noticed the same thing in Ruby and Erlang, or any cross-platform GUIs. Maybe just not enough momentum for that yet.


I mean, Swing is like 20 years old 😛


I'm not sure momentum is what they're lacking


I think its because most of the time, the toolkits have really ugly default styling


And if you want nice styling, there's commercial offering


Makes sense. I imagine it takes a lot of work to maintain a compatibility layer across the platforms that looks fully native on all. In that light I suspect I’ll still be writing Javascript/Dart for a few more years.


Well, Java has all types of GUI toolkits. One uses native controls, one simulates native looking controls. But I'm not talking about that so much, since native look and feel of desktops are also pretty ugly


Most real commercial app is custom styled


This is the best I found 😛


@U0K064KQV you mentioned electron-based, what’s the project there?


There's no framework for it. You just use ClojureScript with Electron directly. A quick google found this that seems like it helps explain how to do so a bit


There's also some lein templates apparently


Though they look a bit old


Seesaw was a nice way to get started quickly building a GUI app in Clojure, and was able to take me pretty far: But it has some quirky non-idiomatic aspects, some of the documentation is confusing, and it is not being actively maintained. Today, being much stronger at both Clojure and Java Interop, I would probably just code directly to the underlying Swing API.


I ended up using Radiance Substance as a custom look and feel, which fit in well with the music/performance application aesthetic.


Couldn't you extend Seesaw to what's missing?


Oh, cool app


Thanks! The problem is that I would want to take some things away while extending others, so it would not be fair to still call it seesaw. And I am way too busy adding features that people are actually asking for to spend my free-time coding budget on a bike-shedding rewrite like that. 😄


Totally fair. I think I'm more curious about, having used Seesaw and swing a lot to make an app like that. Do you even see value in something like Seesaw over direct use of Swing? Like given you had time and money to extend Seesaw to your liking, would you even? Or is direct usage of Swing just simpler in the end?


There’s definitely value in Seesaw, and for getting started it’s faster and easier than learning all the Swing details and tedious Java interop variations. I don’t regret using it, and probably wouldn’t have even started the proof of concept that became Beat Link Trigger without Seesaw to smooth the initial development. The parts I somewhat regret are being tied to it now, given that it probably won’t ever get updated to run cleanly in JDK 11 (due to some reflection on internal classes that violate the new module boundaries) and that it also encouraged me to use MigLayout, a powerful layout manager that it provides a wrapper for, which is also a one-person project that seems to be abandoned, and I worry that the rest of the documentation may go offline any day, as some sites including the support forums already have.


A project to update and clean up Seesaw would be wonderful, and perhaps another to write a nice layout manager in idiomatic Clojure would be wonderful things. It would not surprise me if the Seesaw author would be supportive of such efforts.


Part of the reason things are a little in limbo at the moment, I believe, is due to the overall confusion and aborted projects in the entire Java desktop/GUI ecosystem. A whole lot of energy was lost when so much of the developer community moved to mobile and web applications, reducing the mind-share of desktop apps in a big way, and torpedoing Java’s “write once, run anywhere” dream. Then, Sun and Oracle invested a huge amount of energy into JavaFX as a supposed replacement for Swing, only to abandon that completely a year or two ago and completely removing it from the platform today.


Ya I know, the landscape is a bit weird. Gluon seems to be taking good care of JavaFX for now, but I feel like in a weird way, Swing was pretty solid, and maybe Java should have just double downed on it.


Anyways, thanks the for insight. It's a really cool app you have, with a nice looking GUI I would say.


With its simple syntax, wouldnt that make LISP compilers/interpreters extremely fast?


What do you mean? In general Lisps are pretty damn fast to both compile or be interpreted (though most Lisps are compiled and not interpreted)


But also compilation is very incremental, because the unit is a form, not a file.


Hey all, a few other people and I jumped feet first into a ... rather dense existing project. The original creator set up a bunch of custom ... entities that IDEs are having trouble following. Both intelliJ and VS Code cannot follow their custom functions prepended with question marks. Which are... heavily used in the project. Any advice on helping configure the IDEs to parse them properly? Or any questions you might be able to shoot my way to help describe this better would be appreciated too. 🙂


Hum, entities arn't really a Clojure thing. Do you mean functions?


Please ask in #calva-dev too. I'll be afk a while and this question will be swallowed up here when I am back, I think.


Does ClosureScript run on Node?


Why does this work when destructuring and renaming at the same time?


(let [{wibble :foo} {:foo "bar}] (println wibble))


Are you asking why it is allowed to assign the destructured value of a key :foo to a name that has no similarity to :foo , like wibble ?


In general, programming languages often let you use whatever names you wish for local variables and function parameters, and this is another example of that.


I should have made myself clearer. What is special with this Clojurism that allows the binding {wibble :foo} to take the :foo keyword and put the value of "bar" into wibble. I'm just unsure of the way it works, it looks like the binding is creating a new map, with wibble as the key and being assigned the value that :foo has from the other map {:foo "bar"}. Yet, with let (and bindings), it's like this if [wibble (function etc..)] where wibble will be assigned the evaluation of the function call


It just looks a bit strange and I'm trying to understand why the lefthand side looks like a map


yet it's treated like destructuring into a var called wibble


(bit like [{:keys [foo]} {:foo "bar"}], but you can't rename foo to another name, i.e., wibble, you have to use the form as shown above.


Does that help?


@dharrigan that's just what associative destructuring looks like. consider

(let [{wibble 1 wobble 0} [:foo :bar]] (println wobble wibble))


basically, just how a let binding looks like [binding-name expression] an associative destructuring binding looks like {binding-name key}. {:keys [foo]} is just a shorthand for {foo :foo}


I see I see. I'm trying to understand the shape of the stucture and that helps a lot to explain it


yeah, I always forget how associative destructuring works. I've had this aha moment at least 15 times 😛


so, that shape is for associative destructuring.


I use the {:keys [...]} shorthand a lot


but there are times I need to rename the var, and thus do the {wibble ...} way, and I was trying to understand why that works


a rationale for the syntax working that way: you can only have a given key once in a hashmap, and you can only have a binding visible with one value in a scope


so there's a natural symmetry there from keys to binding names


this also means you can have multiple bindings that use the same keys - sometimes this is even useful I bet


also, if the values were on the key side and the bindings on the val side, a destructure would be "mirror image" in a weird way - with any nested structure all happening in the keys, and the vals all being symbols


thank you for that information 🙂


and it works, simply because that's the form when doing associative destructuring.


I’ve started noodling with Clojure for a while after a long absence. I want to break a string into individual characters, while supporting surrogate-pair characters. I have a solution that mostly works, I’m wondering if there’s something easier that I’m not seeing


Using iterator-seq and .codePoints is much better.


I don't think there's ever a reason to use .toString instead of str in clojure code, btw

👍 4

(Apologies for possibly terribly-formatted code.)

Alex Miller (Clojure team)15:01:33

there is a String.codePoints() method that is surrogate-aware - not sure if that's helpful?


I’ll take a look at that, thanks!

Eamonn Sullivan15:01:56

Hi all, I have a fairly large (probably too large, for a first real clj/cljs project) project that I generated with the lumninus template and a fair number of options (+re-frame +graphql +postgres +shadow-cljs). I'm working through the project slowly as a way of learning the language and the build tools. Is it worth me trying to convert this to cli/deps project instead of a leiningen one? I have a list as long as my arm of things I still don't know how to do and I'm not sure where to prioritise the CLI tools. Is it difficult to convert a leiningen project? Or are there things that Leiningen is giving me that just aren't available yet?

Alex Miller (Clojure team)15:01:52

I wouldn't bother spending time on that. you're likely to run into things that you can do with lein but can't as easily do with clj yet

Alex Miller (Clojure team)15:01:37

Using lein is perfectly fine - I'd stick with that if it's working for you

Eamonn Sullivan15:01:47

Thanks. It has moved to the bottom of the list. I suspect the project I'm trying is big enough that it might be worth spinning off a library or two. When I get that sophisticated, I'll try to do those libs as a deps.edn project.


To my previous question—my head hasn’t been in Java in forever, it looks like Java streams implement Iterator, so it should be easy to interact with them in Clojure, but I’m uncertain about how.


they do not implement Iterator, but you can ask them for an iterator with (.iterator the-stream), and they do not implement Iterable 🙂


Sorry, yeah. I’m in JS-world where “implements iterator” means something somewhat different and I was thinking about it in that way.


(“implements iterator” in JS means it has a property [Symbol.iterator] that’s a function that returns an iterator object)


ah yeah I forget how easy it is in js


Yeah. The thing I want to do in JS is as simple as […stringWithEmoji] 😛


Iterator means you have a pair of methods hasNext() and next(0 Iterable means you have a method iterator() Streams have a method iterator() but do not implement Iterable


which is surprising


That… is surprising


That is really weird. I'm sure there is a reason for that


Does somebody know how to use pomegranate with a standalone jar?




Exception in thread "main" java.lang.IllegalStateException: Could not find a suitable classloader to modify from clojure.lang.LazySeq


The README says something about about "a situation where you are using pomegranate but do not have a clojure.lang.DynamicClassLoader visible in your classloader hierarchy, you will need to explicitly enable the .URLClassLoader support in dynapath (upon which pomegranate relies for such things" but I don't know how to add the support via dynapath.


(let [cl (.getContextClassLoader (Thread/currentThread))]
    (.setContextClassLoader (Thread/currentThread) (clojure.lang.DynamicClassLoader. cl)))
@finn.volkel Add that near the top of your -main function.

👍 4

(it's what Clojure's REPL does and it's what we do in our dev/repl.clj file at work to ensure a DCL context for starting Cognitect's REBL so we can use the add-lib branch of t.d.a. and add new dependencies on the fly without restarting REBL)


Thank you that worked.


What is the status on the add-lib branch? Is that going into tools.deps.alpha anytime soon and if so will it support leinigen or should I rather not bet on that?


Still to be decided, according to the latest from Alex. No idea what you mean about "will it support leiningen"?

Alex Miller (Clojure team)20:01:16

it is actually designed such that you can inject the initial dep context so it could be used from things other than clj, possibly including leiningen

Alex Miller (Clojure team)20:01:50

the plan is to integrate it into tools.deps but it needs some modifications


@U064X3EF3 Currently playing around with the add-libbranch. The following doesn't work

   {next.jdbc {:git/url ""
               :sha "425d1c367c2e7c585cb85b1b379cf5a3a1c49792"}}}
I have to do:
(require '[ :as mvn])
(deps/resolve-deps {:deps {'org.clojure/ {:mvn/version "0.1.5"}}
                    :mvn/repos mvn/standard-repos} nil)
   {next.jdbc {:git/url ""
               :sha "425d1c367c2e7c585cb85b1b379cf5a3a1c49792"}}}


Thanks had not seen that.


@seancorfield But still getting some issues in some cases:

(add-lib 'org.clojure/tools.trace {:mvn/version "0.7.10" }) ;; works
  (load-master 'clojure/tools.trace) ;; doesnt
  (add-lib 'org.clojure/data.json {:mvn/version "0.2.7" }) ;; works
  (load-master 'clojure/data.json) ;; works


@finn.volkel tools.trace doesn't have deps.edn so you can't pull that in with the CLI/`deps.edn` stuff.


i.e., with load-master from GitHub.


(it does have a pom.xml file tho' so I would have expected that to work...)


Hmm, it works just fine for me:

user=> (require '[ :refer [add-lib]])
user=> (require '[ :as gitlibs])
user=> (defn load-master [lib]
(let [git (str "" lib ".git")]
(add-lib lib {:git/url git :sha (gitlibs/resolve git "master")})))
user=> (load-master 'clojure/tools.trace)
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See  for further details.
Checking out:  at e6bc29e4c1d9d69d6d9d7cce62ee8da02662d284
user=> (require '[ :as t])
user=> (t/trace (* 2 3))


@finn.volkel When you say "doesnt" work -- could you be a bit more specific about what isn't working and how it is failing for you?



1. Unhandled java.lang.NoSuchMethodException
   org.eclipse.aether.RequestTrace, java.lang.String,
   org.eclipse.aether.impl.RemoteRepositoryManager, java.util.List)


Sorry I hadn't realized that I have clojure/tools.trace already as dependency in my project. So might be that.


Yes tested it in a clean project and it worked.


Added the dependencies to project.cljof the clean project but still not getting the error there.


Ok it's some dependency issue.


Here are the dependencies of the project.clj where it fails.

:dependencies [[cheshire "5.9.0"]
                 [clj-http "3.10.0"]
                 [clj-jgit "1.0.0-beta2"]
                 [com.cemerick/pomegranate "1.1.0"]
                 [org.clojure/clojure "1.10.0"]
                 [org.clojure/core.match "0.3.0"]                 
                 [org.clojure/math.combinatorics "0.1.6"]
                 [org.clojure/tools.gitlibs "0.2.64"]
                 [org.clojure/tools.analyzer.jvm "0.7.2"]
                 [org.clojure/tools.namespace "0.3.1"]
                 [org.clojure/tools.trace "0.7.10"]
                 [org.clojure/tools.cli "0.4.2"]
                 [org.tcrawley/dynapath "1.1.0"]
                 ;; [tentacles "0.5.1"]
                 [com.github.clojure/tools.deps.alpha "add-lib-SNAPSHOT"]]
  :repositories [["jitpack" ""]] 


These also break it in a clean project.


I didn't think t.d.a.'s add-lib branch was available except via a git dependency.


I wouldn't expect you to need pomegranate, clj-jgit, tools.gitlibs, or dynapath if you're pulling in t.d.a. -- but any of those could be breaking add-lib.


I've no idea how you would do this with Leiningen tho' -- I haven't used it for years.


But it's a git dependency. Maybe I didn't understand you correctly.


I essentially want to mine some clojure code that's why I am experimenting with pomegranate and the clojars api. The other option was to use the add-lib branch and tentacles (github api interface). The git approach would probably give me more code but currently all leiningen projects would not be loadable, that's why I asked.


Do you think one option is better suited/rebust then the other?


I've no idea. I only use add-lib via CLI/`deps.edn` and it just works the way I showed. It can load projects via git that have pom.xml or deps.edn files. It can load projects via regular coordinates from Clojars and Central. I was just trying to help you with it because you were saying things "didn't work" but you didn't explain how they weren't working.


I don't know what you mean by "mine some clojure code" and you didn't state what problem you were trying to solve.

Alex Miller (Clojure team)22:01:56

pomegranate and some other things there use different version of the maven resolver etc - it's highly likely that you can end up with a set of maven transitive dependencies that won't work with tools.deps

Alex Miller (Clojure team)22:01:08

I'd say it's almost certain that's the explanation for the exception you posted earlier (and this may be non-deterministic - moving deps around in project.clj could affect whether you see it)


Yeah, that was what I was suggesting a quarter-hour ago: the dependencies listed in your project.clj are probably breaking t.d.a.

Alex Miller (Clojure team)22:01:39

yes, I'm confirming that :)


Oh, I missed the exception in all the back and forth. I think that came in round about when I switched computers...

Alex Miller (Clojure team)22:01:17

re "The other option was to use the add-lib branch and tentacles (github api interface)." - I don't know how that would work


ok maybe I should explain what I want to do

Alex Miller (Clojure team)22:01:58

well, that's usually a good place to start :)


Starting with a problem statement is often very helpful 🙂


I want to use tools.analyzer.jvm on lots of source code, essentially retrieving information on the AST's paths. Currently I use the clojars api ( to get information on the artifacts I am interested in and the version. Afterwards I load the dependencies via pomeranate. Then find all the namespaces via ns-find/find-namespaces-in-jarfile and then analyze the namespaces via analyze-ns to get the AST's.


It currently feels like a bit hack. I would love to do it more cleanly


The add-lib + github api approach feels cleaner as I have immediatly the information on what is a fork and what not. I can also sort projects on number of stars to get higher quality code etc..


The endgoal is to do ML on Clojure Code. If you think there is also a completely different approach to doing things I more then happy to hear it.


s/bit hack/big hack/

Alex Miller (Clojure team)22:01:04

tools.deps can download the git libs for you, so you don't technically need tentacles at all btw

Alex Miller (Clojure team)22:01:54

well, I guess maybe you're using it for other stuff

Alex Miller (Clojure team)23:01:45

it all seems reasonable to me - but I would just pick one path and kill the deps for the other one to avoid conflict between them


tentacles was more for the meta information of the repositories and also finding repositories, I agree I don't need to actually load the deps


totally agree with the one path approach, I was just not sure in which state the add-lib branch is and what it will support in the end.

Alex Miller (Clojure team)23:01:55

the tip of add-lib branch had master merged into it recently, so it's basically additive to the main line

Alex Miller (Clojure team)23:01:23

I do not have any guarantee or expectation for you on when it will be more officially available


ok thanks anyway

Alex Miller (Clojure team)23:01:02

to be useful, it's api will be approximately what it is now (since there's not much to it)


@U064X3EF3 @seancorfield Sorry to bother once more. So I think there is some issue with the add-lib branch and leiningen. I essentially followed the instructions from your post ( and it works fine on clj. If I do the same thing in a clean leinigen project that has only clojure and the add-libbranch as dependencies I get an error for the following

(ns foo.core
  (:require [ :as mvn]
            [ :refer [add-lib]])

(add-lib 'org.clojure/tools.trace {:mvn/version "0.7.10" })
(require '
The error I get when requiring is:
1. Unhandled .FileNotFoundException
   Could not locate clojure/tools/trace__init.class,
   clojure/tools/trace.clj or clojure/tools/trace.cljc on classpath.
It might have to do with the fact the leinigen depends on pomegranate and that might clobber the classpath somehow.

Alex Miller (Clojure team)17:01:52

You shouldn’t have pomegranate on the repl classpath in lein afaik


Yes it's not the classpath.

Alex Miller (Clojure team)17:01:01

What does the call to add-lib return?

Alex Miller (Clojure team)17:01:42

It returns the things it added


It returns ture I wanted to say.


So there is some version of dynapath loaded via cider.


#namespace[cider.nrepl.inlined-deps.dynapath.v1v0v0.dynapath.util] don't know if that is the issue

Alex Miller (Clojure team)17:01:55

add-lib is designed to work with clj


Sure. I understand that it is work to make it work for every tool out there. Maybe I dive into the problem.


Is it possible to point to a Java github project with deps.edn and have it build so it can be used in the clojure project?


I put in the sha to my deps.edn and it's acting like the library isn't in the classpath

Alex Miller (Clojure team)20:01:30

deps.edn / clj are designed only for source-only Clojure projects and do not include any "build" step


no because Java things require a build step


where does deps.edn clone to so I can build it manually?


~/.gitlibs is where Git checkouts end up.


ok -- so, if I mvn package successfully in the ~/.gitlibs path -- can I then reference it and it'll show up in the classpath, or do I need to drop a jar in somewhere else?


mvn install puts a JAR in appropriate directory in your ~/.m2 directory, where they can be found by almost any tool I know about that looks for JAR files.


But off hand I do not know what happens if you were to take a project that was Clojure source only, create a JAR in /.m2, and then try to use deps.edn to use it -- might be some additional details about how you do it to decide whether it uses /.gitlibs or ~/.m2 version then.


If it has pom.xml etc, it works just fine, because it looks like a regular (maven) artifact and you can depend on it by group/artifact/version.


So it really depends on how "packagable" the Clojure project is...


~/.gitlibs is where Git checkouts end up.


You can sort of use the CLI to compile Java code via an appropriate -e option that shells out and runs javac but it's pretty nasty and likely only works in the simplest of setups...


...some variant of this:

clojure -e "(require '[ :refer [sh]])(sh \"javac\" \"\")(shutdown-agents)"


I did a mvn package in the .gitlibs path and it dropped a jar in target -- do I need to move this anywhere for clojure to pick it up?

Alex Miller (Clojure team)19:01:20

You should not modify the stuff under .gitlibs


well, it didn't seem to pick up in the classpath, so I guess it needs to be moved somewhere


It needs to be on the classpath -- if you do a local mvn install it'll go into ~/.m2/repository and then you can depend on it by group/artifact/version.


Given the path into the project under .gitlibs changes with each SHA, you might be better off manually cloning the repo somewhere stable and adding the appropriate directory as a dependency via :local/root...


...depends on how reproducible you want that to be.


Can I create and pass around middleware chains and connect them to a handler later?


Assuming a typical ring middleware


This closest to that I can come up with is:

(defn chain [handler]
  (-> handler
      (m/wrap-content-type "application/transit+json")))


@mruzekw Yes, middleware is just functions, and composing two middleware functions produces a new middleware function.


So I could just use comp as well?


Hmm, how would that work with a middleware that takes the handler first?


#(m/wrap... % "my" "args") for each middleware


So manual thread-first in a way


I think -> threading is easier to read tho'.


So you would do something like (defn chain [handler]…?


Or is there some comp + -> I’m not seeing?


(defn wrapper
  "Given the application configuration, return middleware that has all the
  things we need configured."
  [config handler]
  (-> handler
      (add-config config)
      (ring-json/wrap-json-response (:json-config config))
       (-> ring-defaults/site-defaults
           (as-> % (merge-with merge % (:ring-defaults config)))


You can use just comp for middleware that only takes the handler...


(but be careful trying to mix -> and comp!)


haha I’ll probably stick closer to the example you just posted


Thank you!


@seancorfield Could I also do something like?

(def chain '[(myapp.backend.middleware/wrap-content-type "application/transit+json")
             (myapp.backend.middleware/wrap... {:param1 "val1"})])

(apply -> handler chain)


You can't apply a macro. -> is purely a syntactic transformation.


If you want to represent the chain of middleware as "data" you could make them all single argument anonymous functions and then apply comp on that


(def chain [#(myapp.backend.middleware/wrap-content-type % "application/transit+json")
            #(myapp.backend.middleware/wrap... % {:param1 "val1"})])

(apply comp chain)


Okay, thanks