Fork me on GitHub
AJ Snow00:01:23

hello! most of the work i've done with clojure has been with cljs. I now have a cljs project with a clj backend and it occured to me, after trying to debug my backend, that I don't really understand anything related to building a clojure application (using the clojure command). Does anyone know of any resources they could point me towards?


When you say "building a Clojure application", there are a few different things. you might mean. At least two I am aware of are (a) using the clojure command to run a Clojure program, given its source code, or (b) creating a JAR file with the Clojure source code, plus any libraries it depends upon, so that it is possible to run the application using only a java -jar foo.jar command, without needing to get any other code from anywhere else. Do you mean one of those?


Option (a) typically requires having the Clojure CLI tools installed on the machine, and downloading dependencies over the Internet from web site, if they are not already cached locally on th machine running the clojure command.


Option (b) requires a step or three to create the JAR file, but once that is done, you only need a Java runtime installed on the machine where the application is run, not the Clojure CLI tools, and no downloading of source or other code required.

AJ Snow01:01:37

(b) is the main case. I need to understand the general semantics for creating jars, running them, and debugging them. Right now I have a clojure backend that throws various errors and I don't have the know-how to understand what exactly the errors mean and how to fix them.


@U012MJU8XNU The best approach with backend code -- Clojure -- is to work with a running REPL and evaluate and test small pieces of code as you build it up.


What you have in a JAR file now is something you could run directly in a REPL and debug it that way but perhaps if you tell us a bit more about the errors you're seeing, we can given you some guidance on how to track down the causes and debug the code.


My first question: is this code in a public repository (e.g., GitHub) where we can take a look and provide suggestions?

AJ Snow04:01:16

the repo i'm trying to learn from is after we build the application and release the frontend app my understanding is you can run the command java -cp fulcro.jar clojure.main -m app.server-main to run the jar for the backend. however, I've run into different errors when trying to do this. right now my problem is a refusal to connect, and it's pointing me to a few different areas when I look at the attached log.


Connection to localhost:5432 refused It expects you to have a PostgreSQL database running somewhere for it to connect to.


The template mentions a "mock database" but I don't see any instructions about setting that up, nor do I see any reference to PostgreSQL -- beyond references to database-related libraries in deps.edn:


Ah, here's the config for your database connectivity: -- so, yes, it's expecting you to be running PostgreSQL somewhere and to update this EDN file to reflect how to connect to that database.

AJ Snow05:01:35

oh, thank you! I wanted to see if I could set up a working page with no data but if I need to set one up I can learn how to I suppose. I was hoping I wouldn't need to set one up, but I guess you can't have a working backend without one.


This is why I tend to recommend learning Clojure without these giant, complex templates. They tend to have so many moving parts that it's hard to learn the language without learning a lot of "irrelevant" stuff about the template instead and all the libraries it builds on top of.

👍 3

I see people trying to learn Clojure via the Luminus template and that's just a disaster most times. These templates make so many assumptions about what their users already know.

AJ Snow05:01:38

I learned mostly vanilla cljs on my own and that was a fun experience, but a lot of the details were abstracted away by stuff like leiningen which made it easier not to get stonewalled. fulcro has been an interesting yet harrowing experience all its own, but now, in particular, I'm having to learn a lot more about build tools and sever management. on one hand i've learned a lot but on the other it feels like it takes so much time to move forward just an inch. not that it's the fault of anything here. it just takes a lot of patience from myself and the others here who offer help. thank you for taking the time! I hope I can get this figured out.

Ricardo Cabral09:01:19

Hello all, Is there any open source project where a beginner can contribute and learn Clojure at the same time?

👍 3

Check out #contributions-welcome

👍 3

would you like learn deep learning and clojure at the same time? Here is the project:

👍 3
Ricardo Cabral09:01:28

Thank you very much


THere's also the #contributions-welcome channel where you can find a list of some requests for help 🙂

👍 3
Clark Urzo09:01:07

Hello, I'm having trouble figuring out how to run an nREPL server using deps.edn:

{:paths ["src"]
 :deps  {org.clojure/clojure {:mvn/version "1.10.1"}}

 {:dev {:extra-deps {cider/cider-nrepl {:mvn/version "0.18.0"}}
        :main-opts ["-m"           "nrepl.cmdline"
                    "-b"           ""
                    "-p"           "5555"
                    "--middleware" "[cider.nrepl/cider-middleware]"]}}}

Clark Urzo09:01:44

I just have to run clj -R:dev then do :FireplaceConnect 5555 right?

Clark Urzo09:01:24

But it doesn't work that way. For the record, I tried it with lein repl and it worked flawlessly.


What is -R ? Also your cider/cider-nrepl seems old. I think the current version is 0.25.8

Clark Urzo10:01:15

run? -A didn't work and -X gave me an error I couldn't quite google:

Execution error (FileNotFoundException) at ( 
-X:dev (No such file or directory)


Someone recently complained about the same error regarding -X and I believe the problem was that their clj version was too old

clj 3

@U014DCEKRGW try clj -M:dev As you can see here: :main-opts is ignored by the other flags


If that doesn't work either, check what you get from clj -Sdescribe and if that's, consider updating your version of clojure

clojure-spin 3

In a nutshell: REPL -> :A main -> :M execute function -> :X If I'm not mistaken, :A is in legacy mode and will eventually be replaced by the other two edit: -A will not be replaced, it will just stop using main-opts at some point.

Clark Urzo12:01:28

Mmm, I'm on 1.10.1

Clark Urzo12:01:49

But let me try updating nonetheless


1.10.1 doesn't say much, did you check the changelog? There are 1.10.1 builds going 1.5 years back! You need the minor version too, e.g.

Clark Urzo12:01:07



yup, that's a year and a day old 😛


and doesn't support -X, according to the changelog (you don't need it here, I'm just mentioning it because you've tried it)

Clark Urzo12:01:49

Huh, figures. All right, I'll finish updating then I'll try again. Thanks.

👌 3

Don't forget to try -M as well, after the update

Alex Miller (Clojure team)15:01:58

@UEQPKG7HQ FYI, -A is not going away (you need it to supply aliases when starting a repl!) but it will stop using :main-opts at some point

😅 3

Oh, that's right, thanks!


Hey I'm trying to sort something like this and its really a mess. Finally I found a "solution" but there is a new problem... There must be a better way out there. This is the input:

(println folders) 
=>(/folder1/folderb/folderb1 /folder3/folderb/folderb1 /folder2/folderb/folderb1 )
(println(str (join #"\n" (sort(split (apply str(join "\n" folders)) #"\n"))))) 
=> (/folder1/folderb/folderb1\\n /folder2/folderb/folderb1\\n /folder3/folderb/folderb1)
The problem is the \\n it should be just \n so what's wrong and is the a more elegant solution? It doesn't feel right this way. This is not really the solution but it works 😉
(join "\n"(sort del-file-names))

Bret Horne16:01:17

Are you trying at add a newline to each folder path in folders?


👍 First I like to sort the folders and then add a newline.

Bret Horne16:01:39

There's a difference between #"\n" "\n" and \n . The first is a regex, the next is a string and the other is a liter character right. A literal newline looks like \newline.


:thinking_face: Ok I'll give it a try. Thank you for the hint.

👍 3
Bret Horne17:01:04

A lot easier to read on mobile too lol

Bret Horne17:01:41

How did you create folders? I expected a list of strings not symbols.

Bret Horne17:01:44

user> (def folders ["/folder1/folderb/folderb1" "/folder3/folderb/folderb1" "/folder2/folderb/folderb1"])

user> folders
["/folder1/folderb/folderb1" "/folder3/folderb/folderb1" "/folder2/folderb/folderb1"]
user> (str/join "\n " (sort folders))
"/folder1/folderb/folderb1\n /folder2/folderb/folderb1\n /folder3/folderb/folderb1"
More aligned with how you’re doign it but note that join’s “\n” is for seperating the values not necesarily appending to each item in folders.

Bret Horne17:01:31

So appending a string to a string you’d use str.

user> (map #(str % "\n") (sort folders))
("/folder1/folderb/folderb1\n" "/folder2/folderb/folderb1\n" "/folder3/folderb/folderb1\n")
‘call str to each item in folders and add “\n” and return the result as a vector’ could use map as well if a list is fine.


Hi guys, is there a way to introspect a function ? I have one function with named parameters

(def toto (fn [& {:keys [filename]}] (println "load filename:" filename)))
I'm looking for a way to do some introspection to discover the :filename inside the function parameter list. When I have a look to cider-inspect, I find a list of static fields I don't really understand. And not sure to know how to retrieve only the value :filename it seems to be a flat list of symbols:
Class: user$toto
Value: "#function[user/toto]"
  "__methodImplCache" = nil

Static fields:
  "const__0" = #'clojure.core/seq?
  "const__1" = #'clojure.core/seq
  "const__3" = :filename
  "const__4" = #'clojure.core/println


That is the cache of constants used by the compiled function


hmm, as I suspected this is not a solution


The destructuring information is not part of the compiled function, it is macroexpanded away


macroexpanded away means "lost"


Yes, it is a one way transformation


Destructuring function arguments becomes a let binding inside the function body that pulls apart and names the relevant parts


The jvm supports annotating bytecode with some debugging information (file, line, and local variable names)


And the clojure compiler does fill in some of that


But the java reflection api doesn't give you access to it, so getting at the info is tedious


ok, I understood


If the function is a defn and you have the var, not just the function object, you can inspect the :arglists metadata on the var


That can be kind of brittle though since that information is part of what doc prints out at the repo, so people have a tendency to fiddle with it to make better documentation, in which case it doesn't actually match the real arglists of the fn


(meta (var toto))
(defn toto [& {:keys [filename]}] (str filename))
is ok. I may have an issue with my english maybe, but I don't understand your last sentence "in which case it..." . @hiredman Do you mean :arglists metadata are not reliable?


For anybody who would be interested in the answer:

(defmacro named-parameters[f]
  `(map keyword ((comp :keys second first :arglists meta) (var ~f))))
(defn foo [& {:keys [filename yop]}] (str filename yop))

(named-parameters foo)