What IDE do most Clojure programmers use who also frequently work in other languages? I tried Calva with Paredit mode but it’s thrown me for a loop to switch to such a different mental model. So I’m wondering if it’s just usual to go from something like Vim style editing when working with JavaScript/Python/Ruby/C++, to a LISP-specific style like Paredit within the same day
@jon920 My recommendation when learning Clojure is always to stick with the editor you already know best, as long as it has one or more Clojure integrations (which vim does have -- see #vim channel and also #conjure which works with Neovim).
Most Clojure developers use Emacs, but I really wouldn't recommend trying to learn both Emacs and Clojure at the same time. I believe there is a vim-mode for Emacs (evil mode?) There's an #emacs channel if you want to get details. There's also a Spacemacs variant of Emacs that quite a few people seem to like.
The next most popular is Cursive for IntelliJ -- but then you're in serious IDE land. And that is followed by VS Code and Calva.
I program in a number of languages and I rely on Atom with Chlorine (after years of using Emacs).
I think the switch in model is due to the language (LISP vs non-LISP) and not to the particular editor used. Paredit is there to help you take advantage of the structural nature of LISP. I completely agree with @seancorfield that if your usual editor of choice has decent Clojure support, then it is best to stick to it, at least until Clojure sits comfortably under your belt. So if vim is your usual goto, you are in luck. If VS Code with VIM Extension is your usual goto, then it can be a bit of setup needed to make Calva and VIM play nicely together, please check https://calva.io/vim/ out for some starter hints. Please feel very welcome to join #calva for assistance from other Calva + VIM users.
Emacs is the best choice.
You’re not alone. I switch between Calva and Emacs. I still inevitably do some line-based cut/paste instead of slurp/barf when trying to reorder a binding block or something and 90% of the time it’s fine, but every now and then I fail to notice I grabbed a delimiter or a #_
and all hell breaks loose.
I’ve never used Emacs, is that like using Sublime Text where you navigate with the arrow keys?
You can use a mouse but it’s definitely heavily biased towards keyboard navigation.
@jon920 Most Clojure developers use Emacs (according to the yearly Clojure survey). There are a number of editors/ide's that support Clojure, so as Sean recommend you should ideally use an editor you are familiar with when starting Clojure. https://practicalli.github.io/clojure/clojure-editors/ However, I did take the opportunity to learn Emacs again when I started, especially as Cider is such a great tool for Clojure development. Developing Clojure is different to other languages and its highly recommend you take a repl driven approach https://practicalli.github.io/clojure/repl-driven-devlopment.html Also, getting comfortable with structural editing makes Clojure coding more effective https://practicalli.github.io/spacemacs/structural-editing/ These concepts are not fully realised or not available in other languages, so their will be some discomfort when switching between languages, especially if doing so several times a day. And of course regular task switching between different applications in different languages, typically with a different design approach, is never got to be as effective as focusing one one language and one app.
I'll definitely +100
that comment about REPL driven.
I'm still confused about print-method
...
When I evaluating the following at the repl, I don't get the results I expect.
clojure-rte.core> (defrecord Foo [x])
clojure_rte.core.Foo
clojure-rte.core> (defmethod print-method 'Foo [v w] (.write w (format "#<Foo x=%s>" (:x v))))
#multifn[print-method 0x23771d94]
clojure-rte.core> (map->Foo {:x 100})
{:x 100}
clojure-rte.core> (pprint (map->Foo {:x 100}))
{:x 100}
nil
clojure-rte.core> (cl-format false "~a" (map->Foo {:x 100}))
"#clojure_rte.core.Foo{:x 100}"
I expect it to print as #<Foo x=100>
I expect it to print as #<Foo x=100>
I have verified that I defined the method in the correct namespace. A call to (methods print-method)
returns a huge map which contains among other things: Foo #function[clojure-rte.core/eval14785/fn--14786],
even prn
prints something strange
clojure-rte.core> (prn (map->Foo {:x 100}))
#clojure_rte.core.Foo{:x 100}
nil
clojure-rte.core>
could it be that my method is on Foo
in the wrong namespace?
hmm. Looks like the system is not calling my method. (get-method print-method (map->Foo {:x 100}))
is returning #function[clojure.core/fn--7252]
rather than #function[clojure-rte.core/eval14785/fn--14786]
what might be causing this?
Its the quote in 'Foo
, remove that and it works for me
cool thanks.
now I get the following:
clojure-rte.core> (prn (map->Foo {:x 100}))
#<Foo x=100>
nil
clojure-rte.core>
However, still returns #function[clojure.core/fn--7252]
... perhaps that function has additional code in it which dispatches on records?
Anyone using Reagent with Netlify?
I’ve done it before. What’s up?
Yes, this very easy.
As easy as a netlify deploy
with a React app :
https://www.netlify.com/blog/2016/07/22/deploy-react-apps-in-less-than-30-seconds/
Just deploy this for eg. https://5f6347c3924ff0b75a89f511--agitated-villani-13169b.netlify.app/
@admin055 I went with calling leiningen in netlify directly so I can customise my build process
@dehli Well, I can't quite make form submission work. I already created a post in the forums but no one has responded :white_frowning_face: https://community.netlify.com/t/no-form-submission-react-via-reagent/22746
@signup867 OK I see.
So you must first add an hidden form with the same name email-address
and same structure directly in your HTML file.
Then you must add an hidden input in your hiccup like this:
Lemme try that real quick
You can see the result here : https://5f6360036041ee823adc4721--agitated-villani-13169b.netlify.app/
You can find more information here: https://www.netlify.com/blog/2017/07/20/how-to-integrate-netlifys-form-handling-in-a-react-app/
I also answer on http://commuity.netlify.com topics so others Clojurists can find the information.
By the way, your project looks interesting. 😉
All right it's building, hold on
@admin055 Thanks! It's my first major CLJS app
Hmmm, so that finally got the netlify forms page to recognise the form
However, I'm still getting redirected to "Page not found" and netlify still isn't acquiring the e-mail address I input
Let me try removing the other hidden input under [:label]
Glad to have been able to help. 👍
Mmm, I'm still not sure why it worked though. When netlify calls leiningen, it should produce a static version of the site thereafter, right?
Or hmm does netlify only look at index.html
when processing forms?
In any case, thanks for the help!
This blog post suggests that conj
should be used to prepend to a list: https://medium.com/@greg_63957/conj-cons-concat-oh-my-1398a2981eab
However, this post suggests that actually cons
is a much faster way (which my own testing also verifies): https://forum.freecodecamp.org/t/how-to-use-clojure-lists-the-list-data-structure/18417
Is there a definitive answer somewhere? The data structures page doesn’t discuss this: https://clojure.org/reference/data_structures#Lists I tried reading through core.cljc
but couldn’t quite make sense of the handoff to Java to find where they’re implemented.
If you want to look for underlying Java implementation details for Clojure on the JVM, then you should look in core.clj
, not core.cljc
. You can also do (source cons)
and (source conj)
in a REPL session to see their source code.
There are Java interop calls with the Java method names there, and the Java package clojure.lang.RT
that they are defined in, which can be found in a source file RT.java
I do not have an authoritative answer for you, but some comments that I don't know how useful they will be.
cons
returns a seq, meaning 'some type, but no promised specific type, that implements the Clojure seq interface', sometimes called a sequence.
conj
returns a collection that is "the same type" as the collection you give it. I put "the same type" in scare quotes because the Java class of the returned collection might be a different concrete Java class, but even then, it should be a Java class that is "the same kind of collection", i.e. a list if the input collection is a list, a map if the input collection is a map, vector if vector, etc.
In contexts where you do not care if you have a list, and any sequence is good enough, then cons
is a reasonable choice. I do not know off the top of my head any places where it is important to have a list rather than 'some kind of sequence'.
I guess one difference is that lists implement count in O(1) time, because the JVM object for a list has a precalculated field storing the count, but many concrete classes that implement the sequence interface do not have such a precalculated count field, so calculating their length takes O(n) time.
There is an old post on SO that explains some of the technicalities of cons vs conj: https://stackoverflow.com/a/12390331
thanks to both of you, this is all extremely helpful
@pithyless Good points there that conj
must realize its 'collection' parameter, but cons
leaves it unrealized. That definitely sounds like a consequence of the "cons for sequence, conj for collection" distinction.
or at least they are strongly correlated -- not sure which way cause and effect went in the design of these things 🙂
Does anybody know anything to parse nested query strings in Pedestal?
It is currently able to automatically turn qs in maps (`?q=1&b=2` => {:q 1 :b 2}
), but I would need something a little bit more elaborate, such as ?foo[bar]=baz
=> { :foo {:bar "baz" } }
Hey team, random q: I notice that if I call a symbol as a function, it returns the last element it was called with:
('foo 1 2) ;; => 2
What is the reason that symbols do this? Was a bit surprised that is what happenedNot sure but
user=> (doc quote)
-------------------------
quote
(quote form)
Special Form
Yields the unevaluated form.
Please see <http://clojure.org/special_forms#quote>
Yields the unevaluated form.
nil
user=> ('a 1 2)
2
user=> ((quote a) 1 2)
2
Ah!
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Symbol.java#L131-L133
symbols and keywords are both also functions that will look themselves up if given an associative collection
so same signature as get
(which also has a second "not-found" arg)
Bam — Makes good sense! Thanks for jumping in team
so you can do ('a {'b 2} 1)
very common with keywords, much less common with symbols
and doubly confusing here b/c 1 is not an associative coll
whether that should throw is a matter of long long debate
is there a clojure command that would fully expand a statement like ('a 1 b)
to de-sugar everything and maybe explain wha the low-level executed expression was?
before i use (replace...) how do i ensure that all the values in the collection are going to be replaced?
that is, each value is a key in the map?
well, there's no sugar - symbols are directly invokable
You could check that all the values are in the collection before executing replace. A function like this might help:
(defn all-keys-in-coll
"Returns true if all keys k are in coll c."
[k c]
(reduce #(and %1 (contains? c %2)) (concat [true] k)))
(= (set ks) (set (keys coll)))
would be simpler, assuming ks
is your collection of keys and coll
is the hash map you want to check.
And if you stick with reduce
, it's better to use the arity with the init
and avoid concat
: (reduce #(and %1 (contains? c %2)) true k)
my other thought was along the lines of do the replace and ensure the values were all different after.
How to compile clojure app as an uberjar when using clojure cli tools and deps.edn? I am hoping to use deps.edn and clojure cli tools for the project. Can someone please point me to an easy way to create a AOT compiled jar file that I can execute using java? What steps do I need to follow. I am trying with a simple app and getting errors like those shown below. I will post the code and errors, but before I do that, I thought I would ask what is the recommended way to do this and try that again with my application. My main goal is to get the application in a format that can be deployed in production. I am assuming that creating a jar/uberjar is the way to do that. I want to know how to get there when not using leiningen. I should add that I am able to run the application using clj -m coffeeapp
without problems when I remove the (:genclass)
line from the namespace.
Syntax error macroexpanding clojure.core/ns at (coffeeapp.clj:1:1).
:genclass - failed: #{:refer-clojure} at: [:ns-clauses :refer-clojure :clause] spec: :clojure.core.specs.alpha/ns-refer-clojure
:genclass - failed: #{:require} at: [:ns-clauses :require :clause] spec: :clojure.core.specs.alpha/ns-require
:genclass - failed: #{:import} at: [:ns-clauses :import :clause] spec: :clojure.core.specs.alpha/ns-import
:genclass - failed: #{:use} at: [:ns-clauses :use :clause] spec: :clojure.core.specs.alpha/ns-use
:genclass - failed: #{:refer} at: [:ns-clauses :refer :clause] spec: :clojure.core.specs.alpha/ns-refer
:genclass - failed: #{:load} at: [:ns-clauses :load :clause] spec: :clojure.core.specs.alpha/ns-load
:genclass - failed: #{:gen-class} at: [:ns-clauses :gen-class :clause] spec: :clojure.core.specs.alpha/ns-gen-class
That error doesn't having anything to do with aot compiling, you have a malformed ns
expression somewhere
You will get the same error just trying to load the file in your repl (assuming your are using the same version of clojure)
@curiouslearn It's (:gen-class)
not (:genclass)
And you probably want to look at https://github.com/seancorfield/depstar as the easiest way to build uberjars with the CLI.
You could add an alias :uberjar
to your project that had depstar
in the :extra-deps
and then :main-opts ["-m" "hf.depstar.uberjar" "coffeeapp.jar" "-C" "-m" "coffeeapp"]
Then clojure -A:uberjar
should compile coffeeapp
(your main ns that has (:gen-class)
in it) and build coffeeapp.jar
which you could run with java -jar coffeeapp.jar
@seancorfield Thank you very much. I will try that out. I did not know about that.
i tend to write function that transform one item, so much of the time though i realize i want elements to "go away" if not appropos, so i have to put (filter some?) in my calling function... so now, i'm swinging toward having functions that return multiple and filter out the unwanted ones in that function. I felt like in Elmlang as well this was always nagging, but don't know clean way to handle.
i suppose i'm being lazy and should write separate filters functions for everything 😞
does keep
help?
Hi all, wondering if anyone can give me tips on dealing with circular dep errors? I find that I am having to quote quite a bit to get around this. Is this expected in most projects or am I missing some key techniques?
Quote what? Quoting effects evaluation, not namespace dependencies
Might be a code layout “smell”
If two libs require each other maybe there’s a third lib itching to be extracted out of them
circular deps seems to be a common problem, but I'm not sure how programs fall into that predicament. typically, you set up all the pure functions needed to get the work done. All of the pure functions are generally independent of each other (which is why pure functions make great building blocks). then you have one namespace that can consume all the necessary namespaces and put everything together. a library like https://github.com/stuartsierra/component may help, but isn't necessary.
a common way circular dependency errors arise is when you define some kind of interface like thing (defmulti, defprotocol, etc), people often make the mistake of putting implementations of the interface in the same file, or trying to making on the implementation namespaces dependencies of the interface namespace
so that would be my guess as how you are getting yourself tangled, but a lot of that is based on supposition and doesn't explain whatever thing you are doing with quoting that somehow solves this problem for you
@seancorfield Thank you so much. I was not sure how to get the :main-opts
working. However, your instructions on depstar
site worked great. If it were not for you, I think I would have given up on Clojure. The language is fun, and I can learn it without problems. However, the tooling is the hardest of all languages I have used (quite likely because I don't know Java). At least, it is great to know that the community is helpful to beginners.
@curiouslearn If Clojure tooling is the hardest you've encountered, I can only say you've been very lucky 🙂 Unfortunately, there are a lot of languages out there with much more complex and sharp-edged tooling!
(as you say, having not experienced Java probably sets your tooling expectations higher)
Thank you for all the feedback. I’m in the following situation with Fulcro:
1. transacting from the UI
2. using merge-component from the mutation which I believe requires a the UI class to merge
I know this may be something I’m misunderstanding with Fulcro, but I thought I would start here in general relating to strategies for avoiding this situation before potentially asking a silly question in there. I know I should probably not be working with Fulcro this early in the game.
Right now I just syntax quote the (comp/transact! [(this add-task...)
so that I can (merge/merge-component! app Task...)
Most hosted languages are super hard to debug without a few years’ full time dev experience IME
Yeah, I think it is because of me not knowing Java. I have not used many other languages; only ones I have used are: Python, Julia, Crystal, Go, and on frontend Javascript and Elm. I guess Python and Julia don't have AOT compilation, so they don't count. Crystal and Go do, and they were much easier to create an executable. To all: please don't consider this as a criticism. Just a beginner's viewpoint, and want to let you know that I am grateful for your help.
@curiouslearn Well, there's also a different set of goals and overall approach in Clojure. There's quite a big push toward run-from-source, since Clojure itself compiles code on-demand. For years at work, we just ran all our production Clojure code from source. Then we started packaging it into JAR files and still ran it from source (`java -cp the.jar clojure.main -m entry.point` calls entry.point/-main
without needing anything except clojure.main
being compiled -- which it is).
We only switched to AOT fairly recently (when I added it to depstar
in fact), to improve startup time -- and startup time was the only reason we did this, so auto-deployed services would come back online in a few seconds rather than a minute or two.
The Clojure CLI / deps.edn
treats source code in git repos as a first class citizen, for example, so you can depend on a project in a git source repo without ever needing it packaged and released to Maven/Clojars, thus avoiding a lot of the Java ecosystem that we otherwise interact with.
You can have a REPL running in a live, production process and evaluate updated code into it while it is running (we do this at work for an internal-facing project that runs as a single server instance and we don't want downtime for small fixes). You can't do that with most languages.
Locally, I develop via the REPL into a running server process all the time. I don't even need to save changes in order to test them: just eval changes into the REPL and try out the new behavior. I can run my unit tests inside the REPL too, so I don't need to leave my editor for that. No "watchers", no "reloading".
@seancorfield Yes. These are some great advantages that I didn't know about. I thought that if it is not AOT compiled, it will run slow. Second, I wanted it AOT compiled so that I could easily deploy it, by just starting the app by running the jar and then using a reverse proxy in front of it. From your example, it appears one can do that even without AOT compiling. Can something like java -cp the.jar clojure.main -m entry.point
be put in systemd
file and expect it to run well? Thank you.
Yes, any command should work. Even clojure -m entry.point
assuming you have the CLI installed on the server and you start it in the project directory. That's basically what we did before we started packaging projects as JAR files.
And we still have quite a few commands we run in production with java -cp the.jar clojure.main -m entry.point
Thank you very much. It is great to know that even clojure -m entry.point
is production ready. What is the difference between clojure -m entry.point
and java -cp the.jar clojure.main -m entry.point
? Thank you once again for the explanations.