beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
fubar 2020-09-17T02:43:38.335600Z

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

seancorfield 2020-09-17T07:23:21.343300Z

@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).

seancorfield 2020-09-17T07:24:46.343500Z

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.

seancorfield 2020-09-17T07:25:35.343700Z

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.

seancorfield 2020-09-17T07:26:24.343900Z

I program in a number of languages and I rely on Atom with Chlorine (after years of using Emacs).

pez 2020-09-17T08:38:05.367300Z

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.

2020-09-17T12:32:32.370800Z

Emacs is the best choice.

chucklehead 2020-09-17T03:00:15.339700Z

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.

fubar 2020-09-17T03:06:54.340100Z

I’ve never used Emacs, is that like using Sublime Text where you navigate with the arrow keys?

chucklehead 2020-09-17T03:15:01.342400Z

You can use a mouse but it’s definitely heavily biased towards keyboard navigation.

practicalli-john 2020-09-17T07:53:49.359200Z

@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.

seancorfield 2020-09-17T08:02:31.360100Z

I'll definitely +100 that comment about REPL driven.

💯 1
Jim Newton 2020-09-17T08:08:30.362300Z

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}"

Jim Newton 2020-09-17T08:08:59.362800Z

I expect it to print as #<Foo x=100>

Jim Newton 2020-09-17T08:14:43.362900Z

I expect it to print as #<Foo x=100>

Jim Newton 2020-09-17T08:15:59.363100Z

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],

Jim Newton 2020-09-17T08:17:15.363300Z

even prn prints something strange

clojure-rte.core&gt; (prn (map-&gt;Foo {:x 100}))
#clojure_rte.core.Foo{:x 100}
nil
clojure-rte.core&gt; 

Jim Newton 2020-09-17T08:18:23.363500Z

could it be that my method is on Foo in the wrong namespace?

Jim Newton 2020-09-17T08:27:25.365900Z

hmm. Looks like the system is not calling my method. (get-method print-method (map-&gt;Foo {:x 100})) is returning #function[clojure.core/fn--7252] rather than #function[clojure-rte.core/eval14785/fn--14786]

Jim Newton 2020-09-17T08:27:30.366100Z

what might be causing this?

2020-09-17T08:28:17.366300Z

Its the quote in 'Foo, remove that and it works for me

👍 1
Jim Newton 2020-09-17T08:29:41.366700Z

cool thanks.

Jim Newton 2020-09-17T08:31:28.366900Z

now I get the following:

clojure-rte.core&gt; (prn (map-&gt;Foo {:x 100}))
#&lt;Foo x=100&gt;
nil
clojure-rte.core&gt; 

Jim Newton 2020-09-17T08:32:16.367100Z

However, still returns #function[clojure.core/fn--7252] ... perhaps that function has additional code in it which dispatches on records?

2020-09-17T10:36:38.368500Z

Anyone using Reagent with Netlify?

dehli 2020-09-17T11:17:08.368600Z

I’ve done it before. What’s up?

2020-09-17T11:20:52.368800Z

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/

2020-09-17T11:28:15.369100Z

Just deploy this for eg. https://5f6347c3924ff0b75a89f511--agitated-villani-13169b.netlify.app/

2020-09-17T12:03:04.369600Z

@admin055 I went with calling leiningen in netlify directly so I can customise my build process

2020-09-17T12:03:34.370Z

@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

2020-09-17T13:12:43.371Z

@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.

2020-09-17T13:13:39.371200Z

2020-09-17T13:18:50.372900Z

Then you must add an hidden input in your hiccup like this:

2020-09-17T13:19:29.373300Z

Lemme try that real quick

2020-09-17T13:19:38.373500Z

You can see the result here : https://5f6360036041ee823adc4721--agitated-villani-13169b.netlify.app/

2020-09-17T13:26:25.373700Z

You can find more information here: https://www.netlify.com/blog/2017/07/20/how-to-integrate-netlifys-form-handling-in-a-react-app/

2020-09-17T13:27:55.374Z

I also answer on http://commuity.netlify.com topics so others Clojurists can find the information.

2020-09-17T13:29:56.374200Z

By the way, your project looks interesting. 😉

2020-09-17T13:29:58.374400Z

All right it's building, hold on

2020-09-17T13:31:11.374600Z

@admin055 Thanks! It's my first major CLJS app

👍 1
2020-09-17T13:33:14.374800Z

Hmmm, so that finally got the netlify forms page to recognise the form

2020-09-17T13:33:43.375400Z

2020-09-17T13:35:04.375800Z

However, I'm still getting redirected to "Page not found" and netlify still isn't acquiring the e-mail address I input

2020-09-17T13:35:54.376Z

Let me try removing the other hidden input under [:label]

2020-09-17T13:44:11.376500Z

Glad to have been able to help. 👍

2020-09-17T13:46:24.376700Z

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?

2020-09-17T13:46:58.376900Z

Or hmm does netlify only look at index.html when processing forms?

2020-09-17T13:48:59.377100Z

In any case, thanks for the help!

2020-09-17T15:49:13.380500Z

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.

2020-09-17T15:58:06.381500Z

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.

2020-09-17T15:58:44.381700Z

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

2020-09-17T15:59:29.381900Z

I do not have an authoritative answer for you, but some comments that I don't know how useful they will be.

2020-09-17T15:59:56.382100Z

cons returns a seq, meaning 'some type, but no promised specific type, that implements the Clojure seq interface', sometimes called a sequence.

2020-09-17T16:01:13.382300Z

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.

2020-09-17T16:02:32.382500Z

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'.

2020-09-17T16:06:06.382700Z

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.

pithyless 2020-09-17T16:47:10.382900Z

There is an old post on SO that explains some of the technicalities of cons vs conj: https://stackoverflow.com/a/12390331

2020-09-17T16:52:47.383200Z

thanks to both of you, this is all extremely helpful

2020-09-17T16:52:55.383400Z

@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.

2020-09-17T16:53:44.383600Z

or at least they are strongly correlated -- not sure which way cause and effect went in the design of these things 🙂

vncz 2020-09-17T16:56:45.385300Z

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" } }

2020-09-17T20:00:28.387100Z

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) ;; =&gt; 2 
What is the reason that symbols do this? Was a bit surprised that is what happened

dpritchett 2020-09-17T20:07:04.387300Z

Not sure but

dpritchett 2020-09-17T20:07:09.387500Z

dpritchett 2020-09-17T20:07:35.387900Z

user=&gt; (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=&gt; ('a 1 2)
2

👍 1
dpritchett 2020-09-17T20:08:19.388200Z

user=&gt; ((quote a) 1 2)
2

1
2020-09-17T20:12:36.388600Z

Ah!

alexmiller 2020-09-17T20:12:44.389100Z

symbols and keywords are both also functions that will look themselves up if given an associative collection

❤️ 1
alexmiller 2020-09-17T20:12:59.389400Z

so same signature as get (which also has a second "not-found" arg)

❤️ 3
2020-09-17T20:13:27.389800Z

Bam — Makes good sense! Thanks for jumping in team

alexmiller 2020-09-17T20:13:30.390Z

so you can do ('a {'b 2} 1)

❤️ 1
alexmiller 2020-09-17T20:13:59.390300Z

very common with keywords, much less common with symbols

alexmiller 2020-09-17T20:14:13.390500Z

and doubly confusing here b/c 1 is not an associative coll

alexmiller 2020-09-17T20:14:40.390700Z

whether that should throw is a matter of long long debate

😆 1
dpritchett 2020-09-17T20:38:05.391Z

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?

Joel 2020-09-17T20:57:42.391700Z

before i use (replace...) how do i ensure that all the values in the collection are going to be replaced?

Joel 2020-09-17T20:58:00.391900Z

that is, each value is a key in the map?

alexmiller 2020-09-17T20:59:28.392Z

well, there's no sugar - symbols are directly invokable

Matthew Cheney 2020-09-17T21:12:04.392200Z

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)))

seancorfield 2020-09-17T21:20:32.392400Z

(= (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.

👍 2
seancorfield 2020-09-17T21:21:46.392700Z

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)

Joel 2020-09-17T21:24:01.393Z

my other thought was along the lines of do the replace and ensure the values were all different after.

Test This 2020-09-17T21:30:32.397500Z

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

2020-09-17T21:32:41.398900Z

That error doesn't having anything to do with aot compiling, you have a malformed ns expression somewhere

2020-09-17T21:33:38.400300Z

You will get the same error just trying to load the file in your repl (assuming your are using the same version of clojure)

seancorfield 2020-09-17T21:36:34.400700Z

@curiouslearn It's (:gen-class) not (:genclass)

seancorfield 2020-09-17T21:37:10.401400Z

And you probably want to look at https://github.com/seancorfield/depstar as the easiest way to build uberjars with the CLI.

seancorfield 2020-09-17T21:38:28.402900Z

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"]

seancorfield 2020-09-17T21:39:31.404100Z

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

Test This 2020-09-17T21:45:46.406400Z

@seancorfield Thank you very much. I will try that out. I did not know about that.

Joel 2020-09-17T21:49:06.408800Z

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.

Joel 2020-09-17T21:50:57.409500Z

i suppose i'm being lazy and should write separate filters functions for everything 😞

alexmiller 2020-09-17T21:58:02.409700Z

does keep help?

az 2020-09-17T22:14:40.411100Z

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?

2020-09-17T22:17:16.413100Z

Quote what? Quoting effects evaluation, not namespace dependencies

dpritchett 2020-09-17T22:17:17.413200Z

Might be a code layout “smell”

dpritchett 2020-09-17T22:17:54.415100Z

If two libs require each other maybe there’s a third lib itching to be extracted out of them

✔️ 1
phronmophobic 2020-09-17T22:20:11.417100Z

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.

2020-09-17T22:25:15.420Z

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

2020-09-17T22:29:12.421800Z

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

Test This 2020-09-17T22:39:17.423500Z

@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.

seancorfield 2020-09-17T22:41:28.426300Z

@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!

seancorfield 2020-09-17T22:41:57.427300Z

(as you say, having not experienced Java probably sets your tooling expectations higher)

az 2020-09-17T22:44:37.432100Z

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...)

dpritchett 2020-09-17T22:44:39.432200Z

Most hosted languages are super hard to debug without a few years’ full time dev experience IME

Test This 2020-09-17T22:46:05.433900Z

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.

1
seancorfield 2020-09-17T22:58:35.436400Z

@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).

seancorfield 2020-09-17T22:59:35.437600Z

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.

seancorfield 2020-09-17T23:00:56.439200Z

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.

seancorfield 2020-09-17T23:03:12.440600Z

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.

😍 1
seancorfield 2020-09-17T23:05:14.442500Z

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".

Test This 2020-09-17T23:10:04.446300Z

@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.

seancorfield 2020-09-17T23:12:34.447300Z

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.

seancorfield 2020-09-17T23:12:56.447800Z

And we still have quite a few commands we run in production with java -cp the.jar clojure.main -m entry.point

Test This 2020-09-17T23:33:14.000900Z

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.