212 comments

[ 4.0 ms ] story [ 230 ms ] thread
I'm glad that Clojure users seem happy with their language. But it seems like a worrisome sign that their survey has roughly the same number of respondents year after year...

* 2020: 2519 responses

* 2019: 2461 responses

* 2018: 2325 responses

* 2016: 2420 responses

Because with modern Javascript you get most of the niceties of Clojure (immerjs for immmutability, lodash for data processing, babel for macros) without the disadvantages (no job market, no ecosystem). The debuggers in JS are so good that you don't need the Clojure repl. JS under v8 is also faster at raw processing(single thread but there are also workers now) unless you write Java with parenthesis, which at that point, you are not writing clojure anymore.

OTOH, Rich Hickey has influenced(in good way) a generation of programmers and doesn't get credited enough.

I've been a Javascript user and fan for a long time. I've used it since it was in beta at Netscape. But one of the disadvantages that needs mention about Javascript is productivity. I have been hands-down more productive in Clojure than I ever was in Javascript.
> no ecosystem

Aside from the entire Java ecosystem? I know using a Java library from Clojure isn't exactly plug-and-play, but that's a bit dismissive. Java has way more code written in it than JavaScript for most things.

And for that matter the whole js ecosystem too. Clojurescript runs wherever javascript does.
True, with time you get good and fast at doing interop, but I can see newcomers getting frustrated with the chore and quitting prematurely because of that.
Your right on those disadvantages instead in the js world you just have to deal with a codebase that was largely developed using the SOCP methodology (StackOverflow Copy Paste) from every "full stack developer" that had a really nice certificate from a 6 week bootcamp.
For what benchmarks are you seeing single threaded JavaScript outperform Clojure on the JVM?
Functional libraries in JS including the ones you mentioned add friction (syntax, dependencies etc.), performance issues and mental overhead. Clojure/Script is designed to be almost completely functional. The code you write is cleaner, more concise and performant almost by default. You also get one syntax to rule the whole web frontend system (js, css, html).

For me the reasons for not using it as a primary replacement are: I get dizzy from interop; it is much more convenient to embed Clojurescript into JS than the other way around. And secondly and more importantly I cannot use it in collaboration.

Debuggers are not a replacement for REPLs. The magic of the repl is to be able to recompile and reload exactly one function or form, for instance. Even if it is really fast most JavaScript setups require recompiling a whole file and likely reloading the whole page to test.

Clojure also has debuggers: you can debug from either Cider or Cursive, for instance. I'm not that familiar with debugging outside of those two though.

> most JavaScript setups require recompiling a whole file and likely reloading the whole page to test

With most setups nowadays (create-react-app/Webpack, Parcel, etc.) and "hot-module reloading" that's no longer really the case...

...but that doesn't take away from your point, because it can have some truly odd effects on the debugger haha

> Debuggers are not a replacement for REPLs.

Nothing is a replacement for a good, "true" REPL. Being able to evaluate any [sub]expression, without any kind of ceremony, anytime, from anywhere in your code is incredibly liberating. Who never used Lisp seriously, would never understand how amazing that workflow is.

I think REPL is the main reason why we still have Lisp dialects. After over six decades Lisp is still alive and thriving.

True! For a long time I was looking for the mythical "livecoding" setup, thinking some experimental programming language was needed or something, when all the while Clojure was there, just waiting for me :-)

In that way I feel Clojure's defaults to immutability go a step beyond what's offered in most Lisp's setups. Not everything "just works" though, thought is still needed in order to have certain things be easily reloadable. I'm talking things like using "defonce" forms and having a setup like described here [1].

I'm still exploring this space but I think the gist of it is to create a direct acyclic graph of dependencies, so you can start and stop exactly what you need, not unlike what build systems do.

1: https://lambdaisland.com/blog/2018-02-09-reloading-woes

You're talking like everyone abhorred Javascript before, and since it has gotten a few "modern" features, everyone (including many Clojuristas) rushed back to it. "Niceties of Clojure" you're talking about have slowly started appearing in other languages as well, not only JS. However, those languages are still missing key ingredients that make Clojure such a nice tool.

Javascript is still a very difficult language to work with. Arguably, it is even hard to rate the language as a production-ready PL. The hidden cost associated with building, maintaining, and scaling JS applications is immense. There are so many inconsistencies and oddities in the language - it is not even cute or funny anymore to talk about WATs or "bad parts" of it. It gives you a false sense of simplicity, it feels like an easy language to start writing apps with, but God, very soon, you realize how awful things are (in comparison).

Clojure(script), on the other hand, is so much more practical. It only looks more difficult, but given enough patience, it brings you stability, consistency, predictability, and, most important - the incredible joy of building working software.

Notably, the majority of Clojurists are seasoned, experienced, tired, grumpy software developers. After trying different options they've finally found something that more or less makes sense. People mistakenly characterize that as a "Stockholm syndrome." Which I assure you is not. I personally use Clojure because it simply makes sense. Once it stops making sense, I will move onto something else. Who knows, maybe Javascript will evolve into something better then. But I can honestly say: "Javascript today does not make more sense." It is not a mere opinion of someone with a cursory knowledge of JS, I've used it (and many other languages that transpile/compile into it) for many, many years.

While my initial reaction would be in the vein of "it's not THAT bad" I just want to say that my experience is very similar.

I have a kind nostalgia for JS because it was my first foray into 'proper' programming (alongside PHP), and I quite like TypeScript. I'm comfortable enough with JS that I can open the dev tools, write a moderately complex chunk of code, and save it as a bookmarklet or private chrome plugin. I'm a JS native.

But good lord do I feel so much better working in Clojure or, day to day, Elixir. There's no way I can comare them to JS and argue for the latter, even with the many improvements since the document.write() days.

> no ecosystem

Today it is possible to run Clojure on:

JVM, JS, BEAM, .NET CLR, Common Lisp runtimes;

Have interop with Python and R. There are Clojure-like Lisp dialects that can compile to Lua and C.

> you don't need the Clojure repl

If you never have experienced the joy of using "true" REPL, you will never understand the immense value of it. Non-lispy languages, sadly have no "true" REPLs.

JavaScript could have one: see the indium plugin for emacs/chrome. The issue in js is that webpack and related build tooling does a really good job of making a repl impossible.
> JavaScript could have one

No, it is still would be very crippled imitation of REPL, merely interactive environment. For a language to have a fully-functional REPL, it is required to have at least some homoiconicity, which JS is not.

Let me demonstrate:

    ReactDOM.render(
      <h1>Hello, world!</h1>,
      document.getElementById('root')
    );
Can you evaluate that in JS REPL? Can you evaluate any part of it?

Now, let's naively "convert" that into Clojurescript:

    (ReactDOM.render
      [:h1 "Hello, world!"]
      (document.getElementById "root"))
You can evaluate every single part of it. You can evaluate "Hello, world!" string; [:h1 ...] vector; document.getElementById function, all these are valid Clojure expressions. In addition to that - Clojure example is so much easier to modify and change. With just a few keystrokes, you can do a lot.

That's basically the workflow - in Clojure, you bootstrap an app with some small, core dependencies, then start a REPL, connect to it and keep modifying your app while running it. That is what gives so much praised productivity boost. It doesn't matter how fast your compiler is (in other languages) - "save & recompile" workflow never going to be as good as working with a "true" REPL.

So the Lisp/Smalltalk approach to organically growing an app.
I've been working with clojure for over a year now and I don't really understand your demo. I think the answer to your JS question (btw the example isn't js, it's JSX, but if we convert it to the js equivalent first) is "yes." You can evaluate the string "Hello, world!"; you can evaluate `document.getElementById('root')` (I do it all the time in Chrome's js console). You can even evaluate `ReactDOM.render` assuming `ReactDOM` is in scope. I don't see any difference between the js and clojure example. What am I missing?

In another comment you gave an example like: (foo [a b] ((c a) b)) stating that you can eval any part of it, but if you try to eval ((c a) b), won't the repl raise an error stating a and b are not defined?

Alright, fair criticism. You're right, I should've probably chosen a different example, but it still would be somewhat difficult to prove my point via text. The REPL experience working with a homoiconic language is definitely better, compared to other languages that have REPLs, it's better than with JS, with Python and even Haskell.

You see, in Lisp you think and operate in units of s-expressions, any s-expression can be send to the REPL as-is, "code is data" <=> "data is code". In Javascript it also adds some hurdles of things being out of scope. In Clojure, due to default immutability - the problem space is usually small, it encourages you to write smaller functions and it is much simpler model - most of the time you can evaluate anything without any preceding ceremony. In some cases you do need to set the context as you pointed with `((ca) b)` example, but it's so trivial to do so with s-expressions and it's so tedious when working with Javascript (trust me, the comparison not in favor of the latter, I've built JS apps for over a decade).

Thanks for the reply. I'm not try to disparage clojure, BTW. I've chosen it to use for my start up, and am only pressing this point because I want to get the most out of it I can and I'm afraid I might be missing something with the REPL workflow. I think I agree with everything you've written here based on my experience.
> I'm not try to disparage clojure, BTW

Even if you were, who am I to judge you? I myself had a chance to learn Clojure back in 2013, and then a few months later, and then once again next year, but I kept saying: "no, thanks". My thoughts were:

- JVM, yikes. JVM means Java, everyone hates Java, am I smarter than everyone else? I hate it too;

- Dynamic typing is so stupid. I've had enough with Javascript, Python and Ruby, I'm not doing that shit again;

- Parentheses. Lots of them. Too many of them. I can't see anything else. I'm drowning in the sea of parentheses.

If only I knew that:

- JVM is actually really robust and extremely good piece of tech; Try managing Nodejs clusters or deal with dependency conflicts in Python's pip. Honestly, JVM is so much nicer.

- That dynamic typing in certain context can be your friend and not the enemy. And REPL driven is much better than "save&recompile" workflow. Besides, there's Spec and it's absolutely dope;

- Parentheses bring structure, simplicity and consistency, and there are not too many of them. Javascript for example has more, and also semicolons and other shit.

Clojure like any Lisp, sadly doesn't do a well job of "introducing itself" to complete newbies. It doesn't look sexy when you're trying it out for the first time. It requires a bit of patience and the leap of faith. And those who are ready to pay that small price, soon may discover an amazing world of possibilities.

> If you never have experienced the joy of using "true" REPL, you will never understand the immense value of it. Non-lispy languages, sadly have no "true" REPLs.

I don't quite understand this, could you explain it a little more in depth?

I tried to explain it in the adjacent thread https://news.ycombinator.com/item?id=22381081

But I think one has to experience it, to understand what makes languages like Lisp and Smalltalk so special, what is so unique about REPL driven workflow that even Python's so much praised Jupyter can't give you that satisfactory feeling.

It's really nice to be able to run anything - from the smallest unit in your program, as well as the whole program and see the immediate feedback. For example: You can evaluate SQL DSL constructs and see what SQL query they compose into, and you can run that query and see the results (all without ever having to write a single line of actual SQL); or you can connect to the browser and change elements of the DOM (without writing a single line of html, css or js).

You can take a complex piece of code that generates a .csv, and then analyze that csv on the fly, changing columns and rows on the go, without even saving and having to wait for the compiler to pass the checks.

You can compose music and data visualizations, and etc.

I think you're taking a tunnel vision view of the language. A lot of languages have a lot of features, but Clojure has just the right set of features all harmonized perfectly together, and almost no bad ones. So it's about how it all comes together.

The secret to this comes down to the Clojure mindset. And where I agree with you is your last statement, Rich Hickey helped push this mindset to other languages, and I'm seeing some of it slowly ramp up in other languages as well. Which is great, but it never comes together as nicely, and who knows where it's going as well.

(comment deleted)
There was something that was said about an old language that I've always enjoyed, REBOL, which in effect is that new programmers adapt to it very quickly but seasoned programmers often have trouble unlearning how they did things in languages they're more familiar with (usually descendants of C). I feel the same applies to Clojure and Lisps in general.

So one reason why the respondents haven't increased much is because its not attracting enough new developers and seasoned developers are giving up too early. Which is too bad because, sure, getting over that initial hump can be frustrating at times but, boy is it worth it! Spending only a few months with Clojure has already made me a much better programmer in the other languages I use.

>>There was something that was said about an old language that I've always enjoyed, REBOL [...]

A few of them went off and were so inspired by REBOL that they created Red[1].

[1] https://www.red-lang.org/p/about.html

There is also bias with respect to survey fatigue. Many of us still use Clojure, but the survey has been running for 10 years, so we are just cranking away, building systems and letting others fill out the survey.
The numbers reflect my anecdotal observations of its usage. I started playing with it in 2014, while working at Amazon. There were tons of repos in Amazon's source control system, and it seemed to be growing fast. By 2016, most of them were effectively zombie services, or dead repos that had been replaced...mostly by java, with a smattering of kotlin and scala. There were maybe one or two teams still using it, but it was very much maintenance mode stuff.
This reminds me of this podcast: https://corecursive.com/david-heinemeier-hansson-software-co...

In it, the creator of Rails says:

> it doesn’t have to be a million person movement for it to be a place where you can live and breathe and work. Um, I mean, I created. Base camp when Ruby had nothing, right? In terms of the tooling that I wanted and I needed to create web applications. I just created all that stuff for myself. By hand. I mean, it’s totally doable

And that's how I feel about my choice of using Clojure.

I have the same feeling, with Elixir as my first choice and Clojure as the mistress, so to speak. It's weird to describe it in these terms, but finding both made me feel like finding a home 'professionally'. I'll happily move to other languages if it's necessary and I keep an eye on how things develop, but I've committed to both Elixir and Clojure when it comes to getting good at something. Because both made me enjoy programming again!
I don't really see anything worrisome about that actually. This indicates that there is a stable community around the language, and while it would be nice for Clojure community to keep growing, it's very much sustainable at this point.

It's also worth noting that responses are indicating that companies using Clojure are getting larger, and more people are using it professionally. This likely indicates that many Clojure startups have successfully grown into larger companies at this point. This is also reflected by efforts like Clojurists Together where companies are funding open source projects that are seen to be strategic for the community.

So, overall I don't really see anything to be concerned about here. Clojure is a niche technology, but the community around it is very vibrant even if it's not growing especially fast.

EDN is a brilliant literal for data, and since it offers more types than JSON, I would love to see it catch on in the places that now use JSON, especially in APIs. JavaScript has a complicated early history and even though one can use objects as a key value map, it’s not quite a map, in JavaScript. EDN does have the advantage of being a clean implementation of its idea.

On a different topic, I’ve read that almost 50% of computer programming work is just building database views and providing GUIs so non-technical people can interact with databases. Making this work easy used to be a major goal of multiple corporate products. One reason VisualBasic had such a devoted following is that it made it so damn easy for novices to build a GUI for a database.

In recent years the industry has moved towards HTML as the default way to build an interface for anything on a network, but HTML continues to lag when it comes to forms. You have to use a mountain of JavaScript to get the form functionality of VisualBasic. We’ve actually gone backwards on ease of creating database GUIs. Yes, in theory you can use something like React to build forms, but the dev using VisualBasic would be done with the project while you’re still waiting for npm to finish downloading your dependencies. And React requires more skill. VisualBasic had a wonderfully gentle learning curve. Likewise, Ruby On Rails (and other frameworks including Symfony and Django) have scaffolding that allows the fast construction of HTML forms, but, again, HTML is a limited method of building forms.

I’d love to see Clojure succeed in this space, building corporate GUIs for databases. How to do that? Is a new GUI technology needed? Towards that end I’d love to see EDN used as a config language to define a scaffold for forms. There are elements of Swing that worked well and could be rescued from the larger wreckage of Java GUIs. And JavaFX represents a huge “road not taken” for the whole industry.

The tech industry has had eras when it focused on opening the door to beginners. Those eras gave us HyperCard and Flash and VisualBasic. Right now the industry seems to be undergoing an episode of gatekeeping. We are requiring beginners to learn React, which is a big eco-system, and also stuff like Docker, which is tough for beginners. The point of making so much tech mandatory for even simple projects inevitably keeps some people from discovering the joy of programming.

Clojure is the most fun language that I ever worked with, and it’s conceptually simple and it has EDN as a data literal language, all of which is a kindness for beginners. If it also had a simple method for building GUIs I believe it could help lead the industry into the next era when we again focus on making programming accessible for beginners.

I suggest taking a look at Cljfx

https://github.com/cljfx/cljfx

It's built around JFX, but it's very Clojure-y (much more than the alternate Swing library). I've been making small GUIs with it and it's convenient and "just works". The only issue I've had is when some callback blows up somewhere in the guts you don't get clean call stacks so it's very hard to debug, but then.. isn't most GUI code? You just need to work incrementally which is easy to do with a REPL

Huh! I've previously only used fn-fx. Any chance you've used both?
Yeah, I actually used fn-fx at first but it's quite complicated internally and semi-unmaintained. I found some bugs/issues and I couldn't figure out how to fix them. Then the project was taken over by a new maintainer but he admitted that he didn't really know how the system works or how to fix it. I similarly read a comment from the cljfx creator that he started the project b/c he didn't know how fn-fx works and how to add to it.

I also wanna say that the CLJFX maintainer is very friendly and responsive and he's been very helpful with all my dumb questions. I thought it's be one of those libraries that gets "finished" and then archived, but he's been keeping at it and releasing new versions for a long while now

The design-paradigm is essentially the same (React-style). You still have a state atom and you're still making a map structure of your GUI elements and then hooking up callbacks to events. I find it's really easy to use, but at the same time I have to admit I don't really get how it works or how to debug the system. It's a bit of a black box for me. You feed in a data structure and it make a GUI for you and functions get called when stuff happen/changes.

Metabase is focused on analytics, which is in a way the dual of forms: https://github.com/metabase/metabase

Clojure has great potential for what you're describing.

could you explain "analytics are the dual of forms" a bit? sounds intriguing!
Ah that was just a bit of a rhetorical flourish.

Forms put data into databases, analytics take it out and do stuff with it. That's kinda like a dual, if you squint and wave your hands enough.

Where VBA is concerned, forms to put data into the database, and analysis/report programs that take it out again, have always been the main use cases.

So, if I get it right, from your comment:

1) You like EDN and would like it to become popular.

2) You would like Clojure to occupy a similar place RAD and 4th gen languages tried to occupy decades back. Not saying this in pejorative way, since I'm sure a big chunk of HN has come to appreciate VB a lot more now that is not such a big thing as it was in the past.

--

Regarding 1), I feel like it is a little bit hard that EDN will become popular, mostly since it goes so much hand in hand with Clojure and its APIs. Plus, in order to talk EDN to browsers, it makes sense to pack it in JSON and then use some clever encoding (like [transit] does). One of the tricky parts of using ClojureScript is understanding the handling of data coming from APIs.. I'm only now starting to get into this but I think is not trivial, and this is why projects like [cljs-bean] exist.

--

Regarding 2), I'm also not sure that the same target market that embraced visual basic and continue to use it will really ever be very happy with Clojure and its ecosystem, since there's not too much emphasis in making things plug and play, is more like a choose-your-own-adventure community :-). I guess it would require a very nice package to market it, the way rails did with ruby.

--

transit: https://github.com/cognitect/transit-format

cljs-bean: https://github.com/mfikes/cljs-bean

> I’d love to see Clojure succeed in this space, building corporate GUIs for databases.

Looks like you’re finding HyperFiddle[0].

Quoting from the website:

> Low-code databases, developer-grade

> Hyperfiddle lets you make lightweight database applications out of just database queries.

It’s Clojure based, uses the EDN notation, and doesn’t require writing a lot of code. It basically translates the Datomic database[1] queries into tables (which can be exported to react components and styled appropriately).

[0] http://www.hyperfiddle.net/

[1] https://www.datomic.com/

No, Hyperfiddle is exactly what I think we need to get away from. This is from their introductory blog post:

"For a high-end UI, use React.js. The above cryptocurrency invoicing MVP generates QR codes using a javascript module from github. This blog post is a hyperfiddle and includes React.js components, CSS, HTML5 video components, mailchimp & twitter integrations"

Hyperfiddle is basic scaffolding of the type we've had for 15 years thanks to Ruby On Rails. I'm suggesting it would be good if we could get beyond this level, since we have been stuck at this level for a long time.

Hyperfiddle does use EDN for configuration, and I really like that part of it, but it's still using HTML, which, as I said above, doesn't give us the form functionality that VisualBasic did.

Some people say that their organization have 100+ people using clojure? Where?
I'm pretty sure it sees a fair amount of use at Walmart labs.
The company I currently work at, FundingCircle, hosts the SF Clojure meetup and uses Clojure for a number of accounting systems.

I’m not a huge fan of the language myself, but it does have it’s strengths.

I guess you mean FundingCircle? How many devs on clojure?
It changes over time with new hires and attrition, but by my last count somewhere between 30 and 40 in the SF regional office. There are more in other regions, but I'm unsure as to the total number.
I think Circle CI uses it quite a lot.
Former Ruby guy reporting in. Started using clojure a few years back, but have been serious about it recently. I can't explain how pleasant the language is. Everything just makes sense, and once you get the tooling sorted (which is admittedly a bit convoluted), it such a beautiful environment.

I've always been an emacs user, so clojure was a match. Emacs + cider for repl-based development has been an amazing productivity boost. I wanna shout from the rafters and tell everyone that this is how it should be done! I don't even want to imagine working in another environment anymore.

The Lisp enlightenment is real, in that I started to see code differently -- more in the sense of homoiconicity. I realized I began to lose the distinction between code and data. Everything just merged. The clouds didn't part nor did I ascend to a higher level of being as promised -- but it was definitely a "whoa" moment.

Enough of my blubbering, just wanna say keep up the good work! The language has brought back the fun of programming for me.

I love Clojure, but I felt like 90% of the time it took me to “learn” Clojure was spent actually learning how to use emacs and working with a REPL. Once you get it down, it’s easy to be super productive, though.
I tried learning emacs when learning Clojure, but found IntelliJ with the Cursive plugin to be a much superior experience (the static analysis is awesome). Been writing Clojure for 3 years now (2 years professionally) and I still prefer Cursive to the alternatives, e.g. Atom, Vscode + Calva, emacs. I would say that most of my colleagues with their custom emacs setups still don't have as a good of a development environment as the vanilla experience in Cursive.

I also use parinfer (https://shaunlebron.github.io/parinfer/) rather than paredit, which makes editing Clojure a bit like editing Python. Rather than memorising commands for structural editing, you instead adjust the whitespace using tab/space/delete and the parens reorder themselves accordingly. You can still use paredit commands while having parinfer enabled, but I rarely have a need to.

I fells for the same trap and I would caution any readers considering learning Clojure, that do not already know Emacs, to not fall for the same trap. It sets you up for a harder road and increases the chance of failing to achieve your goal. Just use Cursive or Visual Studio Code with the Calva extension and leave Emacs for a later date if that is a goal.
Parinfer + Cursive is my strategy too, and I describe it the same way (Pythonish).

This is definitely the least intimidating strategy for ecosystem newcomers.

For folks who don't know emacs, I think it's wise to advise most people to focus on learning one thing and learning one thing well. Emacs is huge and learning it can distract from learning clojure. There is Cursive for Intellij IDEA (my personal tool), Atom plugins (the platform I learned clojure on), Visual Studio Code plugins, even vim plugins. But if you're already a vim user, I recommend Spacemacs as it is well documented and works great with clojure with a next to no configuration out of the box.
Spacemacs is great, just use the dev branch (I think) instead of master.
I am wondering how people deal with complicated domain models, I have many objects that have a lot of properties (from 10 to 30), in Clojure I should represent them somehow, probably with maps, the problem is I would have to memorize all the keys... How this is approached in Clojure in a proper "clojurian way", that is without doing something like using Java classes?
There isn't one way of doing this.

Quickly figuring out if the model is good, I'd start with a map. If I'm feeling fancy I'll add a schema, if I need to I'll convert to a Record. Because of the way the language works you can probably make those changes without significant logic changes. Its a remarkable language.

It is difficult to grasp this from a distance. But generally: you can compose, destructure traverse/query and „update“ (in an fp sense) maps very freely and uniformly. So there is already an opportunity to model your data very differently and to deal with parts of maps in sane isolated ways by querying and destructuring.

Structure in clojure is rather implicit. The benefit is that you can nail down structure where you need it typically with spec.

A helpful hint could be that keywords can be namespaced. This can lead to better uniformity when structuring maps.

Also your dev environment and approach matters here a lot, since you typically run a REPL while you develop, you evaluate forms incrementally and figure out details about your code ad-hoc, which goes way beyond just dealing with names.

Hope that helps a bit.

Most editors should autocomplete those keys for you if you want somewhere that is a centralised location to find those names you could consider using spec https://clojure.org/about/spec

Spec 2 should separate two concepts, schema: all of the possible keys, and selection: the keys used in this particular function, Spec is also recursive

Because spec is part of the language there is a growing ecosystem for defining specification once in spec then translating them to things like database schema, GraphQL schema, OpenAPI schema etc where they can be more "traditionally" understood

You also get other cool things like you can generate conformant data examples given a spec, and use those to create generative tests, as time goes on I think our static analysis tools will start working partially with specs to further their abilities

Specs also power things like this: https://borkdude.github.io/re-find.web/ and I think we're increasingly using them for validation, error detection etc in the core language too

Was going to highlight the same thing. even in OO if you are not using tooling like autocomplete, you have to mentally map all of those attributes. Fortunately autocomplete is fairly ubiquitous and it exists for Clojure as well. Visual Studio Code has pretty good support for Clojure via some contributed plugins.
In OO, autocomplete can be driven by type information, which makes it that much more reliable and relevant.
Any clojure shops in Montreal? Or Canada in general?
I think yogthos (author of Web Development in Clojure (book) and Luminus (web framework) is in Toronto and leads a gang of clojurists.
It's really unfortunate that the Clojurians Slack, being free, lacks good history. So much knowledge is disappearing, or at least becoming inaccessible (I'm sure someone has logs, probably via alternative clients or bots).

Hard to move a community though.

A lot of ppl is active on https://clojureverse.org/ though, but sure, it would be nice to have a permanent log for clojurians too.

Do you have any idea what it takes for Slack to record the history and make it available? Is is very expensive? I know they charge individual users for the service of seeing far back into the past, not sure if they make that free for any particular communities.

Slack's official pricing starts at $6.67 per seat per month, and Clojurians is a very big Slack. Sometimes they comp slacks, but Clojurians is apparently not important enough for that and/or Slack is big enough now they don't have to care :)
The clojurians zulip chat[1] offers a free, full-text-searchable archive of slack.

Also, IMHO it's much better than slack for chatting. If only everyone switched!

[1] https://clojurians.zulipchat.com/

I've actually had a ton of luck with site:clojurians-log.clojureverse.org for searching through the slack history.
Same for Elixir. I actually intentionally ask certain questions on the IRC channel if I think they're worth ending up in someone's search request. It's vexing.
I tried out Clojure for a personal project about a year ago, just to see.

The tooling situation definitely needs some work. Compared to the batteries-included setup of Cargo or NPM, it felt pretty slapdash. The fact that Leiningen is both the go-to and unofficial was a tad bewildering.

Once I got set up, the development experience in VSCode was also quite underwhelming. I've never liked CLI editors and I didn't want to shell out for IntelliJ, so it was my best option, but it didn't offer much beyond indentation and inline eval (the latter was cool, but the lack of basics like autocomplete outweighed it).

These factors obviously aren't as relevant at a company that already has a standard way of doing things, and maybe the situation has improved since I tried, but it really put a damper on the "hit the ground running" experience which is important for gaining initial traction with developers.

All of that said, I can see the language being really pleasant to use in the right context. Most of my hobby projects involve GUIs and/or graphics, so I haven't done any more Clojure since. If that weren't the case maybe I would've put in the extra time to really figure out a good environment for it.

A few of these things may differ from when you tried Clojure out last:

> The fact that Leiningen is both the go-to and unofficial was a tad bewildering.

Clojure now has an official, built-in CLI that mostly supersedes Leiningen.

You can just install Clojure itself, create a 'deps.edn' (which can be as simple as '{}') and get going at a REPL by running 'clojure' or 'clj'.

Packages are auto-installed - in some ways I find it even easier than node, where npm is a separate tool/install sometimes. :)

> Once I got set up, the development experience in VSCode was also quite underwhelming.

There's a VSCode editor plugin called Calva[2] which has developed pretty thoroughly over the last year or so. Outside of IntelliJ/Cursive, it's starting to become one of the more feature-complete systems and it has plenty of features that you'd expect.

[1]: https://clojure.org/guides/deps_and_cli

[2]: https://marketplace.visualstudio.com/items?itemName=betterth...

I believe Calva is what I used, but it's entirely possible that it's gotten better since then
> it didn't offer much beyond indentation and inline eval (the latter was cool, but the lack of basics like autocomplete outweighed it)

It definitely has intellisense/autocomplete now, so that at least is one point of difference from when you last saw it. :)

It saw some major releases and inprovements in 2019, it is worth revisiting imo
Yes, the official Clojure build tool (deps.edn) is amazing. The ability to use local projects as deps is very useful. It allows to split your bigger project into smaller projects and reuse them. It's also possible to use directly git repos as deps which is useful for trying the latest libs.

This, coupled with a REPL driven development gives you a very interactive and agile dev experience.

You only need the free version of IntelliJ for Clojure development. And Cursive is free to use for non-commercial endeavors.

Just in case others were looking. It probably helps to start with IntelliJ + Cursive, instead of trying the lesser featured VSCode and Atom support, or the more difficult to master Emacs + Cider combo or the many VIM alternatives.

No reason to shell out for IntelliJ: The free community edition is all you need, and the Cursive Clojure plugin has a free personal license option.
Clojure is a decent language. I've worked with it a good deal in work. But I would take any functional language with types over it. Some thoughts:

- its dynamic-ness makes it not suited to large projects IMO.

- The currently-accepted attempt at a non-type-system-type-system 'spec' is not well thought out.

- Biggest wins I think are immutability by default, homoiconicity, and "simplicity"

- The repl is fine but can be a crutch -- see startup time

- Clojure still hasn't really found a niche, and I'm not sure I would ever reach for it first unless I was integrating with other clojure projects.

> The currently-accepted attempt at a non-type-system-type-system 'spec' is not well thought out.

This is quite possibly true (I certainly have my complaints with it), but I'd love to hear more about what you're getting at when you say this.

When the canonical example of an fdef takes significantly more code than the function itself, I think you have to re-evaluate your approach: https://clojure.org/guides/spec#_specing_functions
Hm the /amount/ of syntax isn't something I think about I guess, this being a Lisp.

I think they've taken the approach of making the system thorough and capable and this being a Lisp, we users can skin it with any level of shorthand that we please.

Datomic (the database from Cognitect) has a similar approach with its schema, which is quite verbose, but many folks that I know tend to simply write a function which spits out the schema, since it's 'just data'.

I tend to use Ghostwheel [1], but there's also spec-tools [2] and others.

[1]: https://github.com/gnl/ghostwheel

[2]: https://github.com/metosin/spec-tools

That seems an unfair criticism, most of that fdef is about the relationship between the args/return as opposed to just the types.
Perhaps. I was trying to find something pithy to give as an example. It's difficult to express all the things about spec that feel off to me. I'll try to enumerate some:

- verbosity (I think schema does this better https://github.com/plumatic/schema)

- because it tries to not be about validating types of inputs and outputs, and rather treats everything as predicates, it tends to live in a grey area between type validation and unit-testing, and I think hinders both

- it only helps at run-time

- over-abundance of macro-usage

I suspect what you consider a 'gray area', spec considers the whole point. What is the specification for this function? It has a signature and a return value and some behaviour in between. Spec verifies all of that together because it doesn't make sense to do it separately.

Also I'm not sure what you mean about run-time, you can and should use spec as part of your development workflow.

Other two points are totally fair though, and the macros are part of the reason it never got out of alpha before a rewrite.

Fair. I find that I naturally tend to think about the general properties of argument/return values and not just the types (or perhaps equivalently expand the meaning of "type" to encompass such usage) so I like the design, but I haven't yet used spec in anger and so might yet change my mind.
A few years ago I started a personal project of implementing a lot of common ML algorithms in both Scala and Clojure simultaneously. I expected Clojure to be a much better fit for this sort of thing but I was surprised to find that as my codebase grew in both languages the Scala code was much, much easier to understand and maintain. There were a lot of time consuming bugs in my Clojure code that were prevented by Scala’s strong typing. I was able to refactor with a lot more confidence in Scala.

So as much as I like some things in Clojure I’d pick a statically typed language for most jobs now.

I'm honestly curious how Clojure + spec would fare in that comparison. Is that something you looked into?

The reason I'm asking is that while my background the typical webdev stuff, I loved TypeScript. And now while much of my work is backend, it's similarly dynamically typed by default because I'm using Elixir. I've dabbled in Elixir's 'spec' and quite enjoyed some of the benefits Dialyzer/Dialixir offered me, but not enough to be able to tell how beneficial it is in my projects.

More than once I've run into issues that I wouldn't have had if I had used specs, but the fact that it's not a default in the community gives me pause. It makes me wonder how much advantages 'gradual typing' actually give me over just being a more thoughtful developer.

It’s an interesting question. I’m not sure if the spec stuff existed at that time. Like you say I think it makes a big difference if it’s built into the language. Typescript is a lot more useful now that it’s become so mainstream, for example.
This is the best argument I've seen for dynamic types beyond the prototyping phase: https://lispcast.com/clojure-and-types/

Not sure if I'm 100% won over, but it makes some good points, particularly the section about JSON. Using TypeScript at work, one of the most painful (yet quite common) things is dealing with foreign JSON from an API, which is sometimes just... wrong. And then all our carefully-typed code falls to pieces.

The argument is that in a language like Clojure you can skip pretending to make guarantees about messy external data, and trade that for simple and elegant traversal code. Probably this is why dynamic languages tend to gravitate towards "glue code" use cases while static types gravitate towards insulated systems with minimal surface area to the outside world (compilers, anyone?).

Any bit of JSON either resolves to a valid object of some type in your data model, or is erroneous. "Simple and elegant traversal code" often makes assumptions about the data it operates over; when handed JSON that violates these assumptions, the result is undefined. If you use the "parse, don't validate" pattern (https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...), by walking the complete data structure early on and ensuring via the type system that the assumptions hold, or failing, your JSON handling code is much clearer and more robust.

Static types are an unmitigated win, if you know how to use them.

Makes me think a bit of Python's "ask for forgiveness not permission".

I have a few problems with "validate then do something if its valid". On top of what that article mentions, there are concurrency issues (e.g. checking to see if a file exists, then if it does, open it... oops, race condition), and general ergonomics (if I always have to do something before I do something else, there should be a function call that effectively does both).

Wouldn't work if you were implementing a library like Pandas when the data can be almost any tabular structure that you need to clean and wrangle into shape before you can be sure what types you're dealing with.
Type systems give you a way to specify what you know at design time. If "has any tabular structure" is all you know then that is what you specify.

I don't think "but my data is dynamic" is a good argument for or against dynamic typing. It's an entirely separate issue.

> but my data is dynamic

In my experience, most dynamically types code makes assumptions about structure that may not hold later (better have tests!) and when it breaks some kind of validation is needed anyway to select between the correct version of the different dynamic options. In static languages this is simply typically done sooner, since the type system requires it to parse the data. (Or it’s in variants that are accessed without checking that the accesses are valid, sigh)

The type system depends on the kind of data you want to keep around in your columns, which could be a mix of types, and it could be all strings and NaNs, for example. This is common with DataFrames. There's a huge number of possible combinations of data you could be reading in that you need to clean up, reshape and then analyze. And you might be making decisions on how to do that in the middle of your wrangling. It's just like what you can put in Excel or a CSV.
I know. I've been doing this sort of thing for most of my adult life.
You have to be sure, like always. You can't write the code dealing with the data you have no clue about.

The type reflects invariants, constraints given for you data. The less you know, the more general type your data would have. Dynamic typing gives no advantages here safe for providing a super-general ANY type.

In case of statically typed language you would need to parse your data and construct an object representing that data just like in case of dynamically typed one. But the more you know about your data in advance, the better, especially when you are dealing with protocols and communication.

> But the more you know about your data in advance, the better, especially when you are dealing with protocols and communication.

The point of a library like Pandas is that you will be cleaning and reshaping your data until it's in a format that can be properly analyzed. And that data can be very dirty and very large.

But if you prefer to clean it up in Excel or with some bash scripts, or custom written functions in PL of choice, then go for it. You still have to deal with the cleaning and wrangling. The point of mentioning Pandas is that you don't always have a guarantee on properly structured data where you can predefine the types and read it in. And you don't always have control over how that data comes to you.

All data has SOME structural metainformation that can be captured in a type. If you are importing a CSV file, you know -- at a minimum -- that it's a CSV and can be parsed as a set of tuples of variants (or else there's something really wrong with the input and an exception continuation should be invoked to handle it). From there you can do analysis on the data to further refine its type.

But ALL data is typed, and encoding its type early in the code that processes it makes your assumptions clear and compiler-enforceable.

You're right that a typed approach to handling arbitrary input data is not right for a library like Pandas. It's a fundamentally different approach than the one Pandas takes, but it's no less valid and brings with it certain advantages.

For the library, you are right, it has to support any tabular structure — but that’s what even ricks are for, to encode that there are parts that you don’t know until use.

When using the library, though, there is some level of assumed structure (otherwise your code wouldn’t work since it would be accessing fields that don’t exist. Sure data is messy in real life, so you encode that messy-ness into your structure as variants or optional that you then check, and ideally are forced to check so that you can’t silently let errors slip in).

This works in statically typed languages right now using generics, templates, types that aren’t inferred until the library is used, or whatever the specific language has to deal with this.

I don't understand your JSON example.

If your Clojure code expects an API response's json.{id,username} to exist, and to not exist is a hard violation of your assumptions and thus your code, then how is that any different from formalizing it into:

    struct UserResponse {
        id: Int
        username: String
    }
?

(Damn, rest of the comment is pretty long but let me try to both sympathize and present a solution that I do like).

What I will say is that most statically-typed languages I've used do get annoying when there's no 1:1 mapping between your struct and the JSON body. I've dealt with some hairy JSON, like APIs that accidentally re-encode nested JSON strings so they become like triple escaped. Or values that can have like 5 different shapes so you really just want to try 5 different decoders until one is successful. (These cases are trivial in my upcoming code example)

For example, Rust's serde and Swift's Codeable are both pretty annoying if you want to apply arbitrary transformations between JSON response -> your canonical representation. Serde, for example, has you implementing the whole trait + visitor if you need to do anything the cute decorator DSL doesn't support. Or you implement a bunch of envelope structs even though you just want to pull out the value at "obj.a.b.c". Or, what happens when you can't simply use a codec from https://app.quicktype.io/?

JSON decoder combinators (e.g. in Elm) make JSON pleasant again while retaining static typing. https://package.elm-lang.org/packages/elm/json/latest/Json-D...

For example,

    data Role = Member | Admin

    data User {
        id: Int
        username: String
        role: Role
    }

    -- API example body: { id: "12", role: "a", info: { uname: "foo" } }
    decodeUser : D.Decoder<User>
    decodeUser =
        User
            -- Crappy API gives us either an int or a string
            (D.field "id" (D.oneOf [ D.int, D.string |> D.map parseInt ]))
            -- Pull out value from nested object
            (D.fieldAt [ "info", "uname" ] D.string)
            -- Arbitrarily transform value and create our own error
            (D.field "role" D.string
                (D.andThen (\value -> 
                    case value of 
                        "m" -> Ok Role.Member
                        "a" -> Ok Role.Admin
                        unknown -> Err ("Unexpected role " ++ unknown))))
That almost compiles despite shooting from the hip directly into this textarea, but the point is that it's a pleasant way to decode JSON while allowing arbitrary transformation, and I think it's the ultimate middleground between static-typing and the sort of on-the-fly decision making you get with dynamic typing.
Your example isn’t tied to static typing, it is simply but behind-the-scenes checking types at runtime. You can do that in any good dynamically typed language (e.g Common Lisp) and hide it in a similar way.

Closure has definite problems that other Lisps don’t due to a combination of leaky JVM abstractions (incomprehensible stack traces, JAVA pollution), its semantics not really being Lisp semantics and its premature optimization into one paradigm that doesn’t really fit the language or most problems very well.

Yes but once the json has been validated once at runtime, you know it's safe for the rest of your program to use.

Whereas in a dynamic language (even an immutable one), your data could be mutated during program runtime and no longer conform to the type you expected. Yes you could re-validate it everywhere, but that requires you to exercise every code path when testing at runtime to find bugs.

I think the general argument that "You can't static type everything (like your API dependencies), so there's no point in doing it all" isn't a very solid one.

Your data can't be mutated if you're using immutable data structures. Which is what Clojure defaults to, in fact.
I didn't mean literally mutating the same structure in place - but a new version of your data structure could be returned from a function which changes some of the keys/values in unsafe ways.
Sure, my example isn't tied to static-typing but static-typing is especially helpful any time you're workin with combinators/transformations at a distance. But also, statically-typed languages like the two I brought up tend to be in most need of a nice validation/codec/transformation library because you can't simply procrastinate establishing your domain models like you can in dynamically-typed languages. And this is the sort of pain that leads people to say that dynamically-typed languages are more accommodating here.

Though I will have to defend Clojure from your last paragraph. I don't think there has been a lisp that has done so much for lisps than Clojure. For example, until I used Clojure, other lisps were just like any other dynamically-typed, mutation-heavy language. The idea of just shuttling around data and transformations on that data is something that fundamentally changed my approach to writing software.

I can certainly come up with worse things to say about Clojure. I kinda grew out of dynamic-typing, for one. And this is never more obvious than if you've ever read a large or complex Clojure codebase while dying to just know what the underlying Java types are. And you're so desperate that you get excited when you see a single ^ChannelHandler type-hint.

Different strokes for different folks I guess. I would take it over Haskell and Scala any day. Haven't tried F# or OCaml so can't comment.

> its dynamic-ness makes it not suited to large projects IMO

I'm really curious about this. I work on large Clojure projects, and it works quite well. We have low defects, and quick pace of change. Maybe we're just lucky, touch wood.

> The currently-accepted attempt at a non-type-system-type-system 'spec' is not well thought out

If you thought of it as a type system, than it's normal you think it's not well thought out. It isn't trying to be a type system at all. It's a contract system. The goal is validation, generative testing, formal spec, parsing, etc. Not type checking. Even given a strong static type system I would still use it.

> The repl is fine but can be a crutch -- see startup time

Heard about this from some people, but dunno, it never affected me. I start my REPL at most once a day, often less then that. So waiting a few seconds doesn't bother me.

> Clojure still hasn't really found a niche

That's true. That said, it is great at everything. While it didn't find itself a popular sub-domain to dominate, I now choose it for everything. There's barely anything it can't handle well. I reach for it for everything nowadays. That's actually something I really like about it, it has huge reach.

I went pretty much all-in for Elixir/Erlang, but I do have to admit Clojure has always been a close second, and I envy the amount of interop it has.

There's various initiatives in the Elixir ecosystem, and tools such as LiveView make my life a ton easier, but man do I wish I could use Elixir as flexibly as Clojure!

> But I would take any functional language with types over it

Which is what? Scala? Haskell? OCaml? F#? Typed Racket? Idris?

I think Clojure really hits the sweet-spot between stupidly boring, "pragmatic" PLs and idealistic, novelty, academic ones.

Haskell is awesome, but realistically it is really difficult to quickly train someone to the point of them being able to write production-ready Haskell code.

Scala has its own warts (besides, Kotlin seems to be slowly eating its pie);

OCaml still struggling to get any recognition in the industry, despite all attempts from a few good players.

I disagree with the notion that Clojure is not suited for large projects, but I agree that Spec needs to be improved (and it is being actively worked on). And I don't think it is not well thought out. Rich Hickey is famous for slowly, carefully, patiently designing things. Stability and predictability of Clojure and its standard library is phenomenal. For every single language (even those I have never worked with) I can probably name a thing or two off my head that involved breaking changes. Not for Clojure.

>>Which is what? Scala? Haskell? OCaml? F#? Typed Racket? Idris?

These days Java works just fine. Why use anything else, that neither has dev mind share nor the library ecosystem remotely the same as Java.

The library ecosystem is accessible from the many compile-to-JVM languages.

Half tongue-in-cheek, half serious: not having Java's dev mindshare is actually a benefit.

When I was last at a Java shop, we we're pushing multiple-thousand line PRs every week, a good 40% of those lines were simply boilerplate generated by IntelliJ, and it would have been worse had we not fully instrumented our codebase with Lombok, and all this was for a pretty mature product that wasn't seeing any radical changes from day to day. At the clojure shops I've worked at since, we're building more and delivering product faster, and we're doing it on the JVM with less than a third of the lines of code. A thousand lines of clojure is a significant refactor or a big feature. A thousand lines of java is wednesday.

For me, clojure provides a simple-to-use API, high-level functional abstractions, an instantaneous feedback loop, access to a battle-tested JVM ecosystem, and more than fast enough performance. This is its killer combination, in my opinion. The immutable-by-default data structures are also an underappreciated boon for writing multi-threaded code without breaking a sweat.

> When I was last at a Java shop, we we're pushing multiple-thousand line PRs every week, a good 40% of those lines were simply boilerplate generated by IntelliJ

This actually one of the things I like about Kotlin - many of it features are similar in effect to pre-generated boilerplate - but it lives as part of the run-time, not in your code.

On the flip side, a new version of Kotlin could potentially introduce/reveal bugs - but at least you don't have to deal with four different generations of outdated boilerplate when diving into old code...

I don't understand how anyone can stomach Java, especially when Kotlin exists which has the same ecosystem as and better tooling than Java.
Unfortunately companies choose Java for conservative reasons which pretty much rules out anything like Kotlin making a dent in Java's mindshare. Most Java shops won't even upgrade beyond Java 8 so switching to Kotlin is a non-starter outside the Hacker News echo chamber.
> Which is what? Scala? Haskell? OCaml? F#? Typed Racket? Idris?

If I want JVM interop, I'd use Scala. Or yeah, as you mention, Kotlin isn't so bad either.

For a fun project, I'd use Idris, Haskell, or Rust (of course, many people may not consider Rust a functional language)

On the frontend, Elm or Purescript.

> I disagree with the notion that Clojure is not suited for large projects

True, large projects can be maintainable or unmaintainable in just about any language. But there's a reason dynamic languages like javascript, python, ruby, and php are seeing such heavy investment into gradual typing: it's helpful to have easy-to-digest information about the shape of data going in and out of functions. Almost nothing about spec is immediately self-evident -- it just gives you more code to read and reason about.

> Haskell is awesome, but realistically it is really difficult to quickly train someone to the point of them being able to write production-ready Haskell code.

A former colleague once said that many companies using Haskell don't really want to spend money training existing developers to learn Haskell; instead they want to hire programmers self-motivated enough to learn Haskell on their own.

> Which is what? Scala? Haskell? OCaml? F#? Typed Racket? Idris?

We have one 100k loc project in Clojure and one 500k in OCaml and I would choose OCaml over Clojure any time any day. I really like that things don't brake accidentally when somebody changes code, and the amount of tests you need to write are orders of magnitude smaller.

> OCaml still struggling to get any recognition in the industry

So does Clojure. Both are extremely niche below the radar languages, so it's not a dichotomy really.

There is a dichotomy of choosing OCaml or Java/C#, but Clojure would be on OCaml's side of things here.

Today, if I'd need jvm, I'll simply take modern Java.

> despite all attempts from a few good players

The few players we have (JS, Facebook, LexFi, Citrix, unis) are doing well enough producing enormous amount of high quality libraries. At least in the domains of system programming OCaml is tightly packed with all sorts of batteries.

> Today, if I'd need jvm, I'll simply take modern Java.

100% Kotlin. Doesn't even have to be Clojure or ABCL.

> Clojure still hasn't really found a niche

To me Clojures sweet spot was dynamically typed, functional programming with an extremely large ecosystem of tools (due to Java interop).

That’s not a niche, that’s a summary of the language.
Tools designed for a statically typed object-oriented language where mutable state is encouraged. I don't see the value for a language like Clojure.
If you are the type of person that fiddles with Clojure and other functional languages (OCaml? Haskell? Scala?) I'm pretty sure you will change your mind on and off, in different seasons of your career :-)

I used to think only languages with good algebraic data types (mostly ML based) where worth my time... but types can really become an straight jacket in large programs and become tedious to use. Clojure code, when reasonably well structured, is not a bad solution for a lot of varied problems, and is beyond great for personal projects! Low ceremony, fast feedback loop, excellent performance, and a huge library of ready made quality libraries.

Quality libraries built with a statically typed object -oriented language designed with mutability in mind. See the puroblem?
Honestly I don't think it is a problem. There's no perfect software and neither type systems nor immutability guarantee correctness. Clojure offers best of both worlds by minimizing and managing mutability.
Having to maintain more than 42k LOC of Clojure code, couldn't agree more. I would also add that i haven't see a community with such fanatism towards a language and his creator. So i always avoid to interact with the community.
I don't know what you're talking about. I've personally worked in several language ecosystems and interacted with members of their communities. Clojure people are one of the most humble, reasonable, friendliest people in the entire CS universe. Many of them have years of experience working in different languages, they are not fanatics, most of the time their answer to the question "is that the right way?" would be "it depends."

While devs in other programming language ecosystems either debate endlessly or rush to add more "features" to their language, Clojurists quietly make things that simply work.

If you follow the trends and dig a bit more, you realize that Lispers carefully filter out good ideas and put them into use, they know how to tell the difference between a brilliant idea and a fad.

And there's no fanaticism and worshiping of language creator. Only respect and gratitude.

> - its dynamic-ness makes it not suited to large projects IMO.

Clojure can be typed https://github.com/clojure/core.typed/

> - The currently-accepted attempt at a non-type-system-type-system 'spec' is not well thought out.

Spec is not a substitute for a type system. It is much more loose, since you are just dealing with implicit predicates but at the same time it is more powerful than what mainstream type systems give you in terms of validity and expressiveness.

Looking at spec through the lens of a type system is weird because types solve two problems where spec solves one problem

So I'm getting the most leverage out of types when they solve: - Static analysis - Specification

Clojure's static analysis tools do use type analysis since the underlying primitives are typed, but a good static analysis does type analysis and other checks so types aren't the be all end all there

Personally I love types that track to primitives, the problem with types is when you let developers use them to express their Person class or whatever, your Person class is not as fundamental as that language's int class, for example, the semantics are completely different between your primitive types but not your Person class vs your Address class

Anyway what I wanted to say is I have yet to meet a type system where I'm happy with its specification capabilities without moving into slot based programming or so much syntax for the types it becomes overhead to read them, i.e. you can write complete programs in TypeScript's Type system

Spec is the competitor for type specification here, it is much nicer you can translate it into API, GraphQL, Database schema etc but it's still getting work for Spec 2, but you can generate data examples out of it, use it for generative testing, use it for parsing, validation etc It's good if you have that specification problem

The static analysis problem is getting more and more attention through clj-kondo and inbuilt analysis via Cursive and other editors, they'll stop you from doing things like (inc "hello world") because you can't increment a string, I think this feature is actually why people love types so much the fast feedback for silly mistakes is soo good and we have that too

What we didn't do was complect those two things together, it also doesn't mar our thinking, I don't think there's an end game where a sufficiently smart type system where it eliminates all programming problems, the next breakthroughs will be in data, not types see the whole area of deep learning, but we're so in love with types we create languages where their USP in the type system

When you get heavy into types you start seeing the world through the lens of types and that's super dangerous for the same reasons that trying to view the entire world as SQL tables is not a maintainable solution, the problem isn't reality it's your lense that you're viewing the world with

Also please don't read this as types are bad that's not what I'm saying, or tables are bad, letting them consume your thinking means you start thinking about problems in terms of typed or not typed boolean thinking instead of nuanced, since nearly all languages are "typed" at runtime and static analysis time anyway

I would pick Clojure over any statically typed FP language simply because it's far easier to train news devs for it. My team has been using it for close to a decade now, and we've only hired a single person who already knew Clojure during that time. All the other devs came from mainstream languages, and we were able to get them productive within a couple of weeks on average. There's simply no way I could teach a language like Haskell in a couple of weeks and get somebody reasonably productive with it.

Monolithic design is not a good way to structure projects IMO. Any large project can, and should, be broken down into small isolated components that can be reasoned about independently. Not only does this reduce overall mental overhead of understanding the code, but it also makes it much easier to reuse. Static typing appears to encourage coupling via the types due to them having to be expressed globally. So, it naturally steers the design towards building a monolith.

I also completely disagree that the REPL is some kind of a crutch. It's a strictly superior workflow because it allows you to put the application in a particular state, and then develop functionality against the state you've already built up. Having to restart the application, and rebuild that state every time you make a change is simply not a productive way to spend your time.

Finally, the claim that Clojure hasn't found a niche is pretty weird seeing how it's used all over the place by companies big and small. It's certainly found a very nice niche in space of web development and companies like Apple, Atlassian, and Walmart are getting pretty good mileage from it.

Clojure Spec is what C++ 20 concepts is evolving to! The idea that there are no truly fixed types but concepts with constraints and requirements.

This is around 5/10 years ahead of its time in the general PL community.

Interesting perspective on spec since I find it very well designed, very consistent, and very useful. What isn’t well thought out about it?
I started writing Clojure professionally last year. It's an incredibly relaxing experience. I attribute that to most of the code being pure functions that operate on plain data types (maps, lists), combined with the delightful experience of structural editing.

My largest issue is spec.alpha, which is far from perfect. spec-alpha2 should fix many of my complaints, so I'm looking forward to its first release.

Clojure is hands down my favorite programming language till date, and I've used a handful at this point. Got professional experience with C++, C#, ActionScript 3, Java, JavaScript, Scala and Clojure. And I've toyed with Python, Kotlin, Rust, Haskell and Elixir a fair bit. Still, I'd say Clojure is my top. Its just well thought out, to the point, and so fun.

Wish the core team many more years of work, and I hope the ecosystem stays afloat, and prospers.

Also, kudos to never breaking my code! That quality is so underappreciated.

Learning and switching to Clojure as my primary language is the best decision I've made in my career (which is relatively short at 10 years, I'll admit).

It's probably somewhat decreased my earnings compared to trendier languages, and I worry that the market for Clojure developers is small and fragile which might bite me in the future... but I've never been happier doing my job than I am since I've started working with Clojure!

- The language itself is beautiful to read and write, minus a few warts that take some getting used to here and there.

- The jobs that are there tend to be smaller teams at larger companies which is my preferred type of setup.

- The community is mostly self-selected and tends to be fairly friendly.

- Working with the REPL feels like having a conversation with your computer, teaching it how to do what you want it to do vs fighting with a compiler.

- I like the "batteries not included" ethos - everything is a library and I can pick and choose what I like.

- Working on the JVM means I get access to untold thousands of Maven packages plus the JVM itself which is a very solid system.

> It's probably somewhat decreased my earnings compared to trendier languages

Odd, considering that Clojure is the best paid language according to the Stack Overflow Developer Survey:

https://insights.stackoverflow.com/survey/2019#work-_-salary...

https://insights.stackoverflow.com/survey/2018#work-_-salary...

That effect is probably much more so about where the language is used (US vs elsewhere primarily) rather than how much people get paid for that language in a particular place.
I find that at least in The Netherlands the vast majority of job offerings are quite conservative in their 'stack'. It's nice that they are now okay with React rather than only Angular, or Python instead of just PHP, but finding a Clojure or Elixir shop is still much like finding a unicorn. And my impression is that this is true in most of the EU.
We have a few in Copenhagen. I've worked at a small startup using Clojure and a big government project using both Clojure and ClojureScript. I've also interviewed at one of the big car pooling apps here and they used Clojure. Now I'm working at a university also writing my code in Clojure and ClojureScript.

But you do have to be diligent and spend some time to search for them. That stack you mentioned is definitely extremely common here too. And in the uni department where I work now the existing research code is still all LAMP stack and Java, so I'm trying to skip a generation of tech and get straight to modernity by introducing Clojure here.

I'm a Web developer the most of the time and I tried to jump back and forth between languages and communities in my spare time to check out if there are some ideas that could interest me. I found dynamic language communities are most inspiring to me, just like the old Ruby community.

I found the Clojure community is really fun. I tried Fulcro/Pathom, it's like GraphQL but much more flexible. And also there are open-source alternatives to Datomic like DataScript in the browser, and Crux is also very promising. I always wonder what if we bring some Prolog/Datalog to day to day programming, and those are the ideas well implemented and polished.

Another interesting community I found is Elixir, Phoenix Liveview is very fast to not only prototyping but also achieve high performance.

As a comparison, most statically typed languages community spent most of their time climbing the lambda cube, or in another word, struggle with correctness and expressiveness. It's not necessarily a bad thing - on the contrary, it's applausable. But I found most of the statically typed languages are focusing on those similar things rather than exploring new directions with would be more weird and fun.

This survey reinforces a positive feedback loop. "Clojure is great because Clojure is great".

For a "state of X" survey it would be nice to see questions like "what are the biggest hurdles, problems, issues". For example, State of JS drills down to language features, syntax, overall happiness, frameworks etc.

E.g. the author of Rum and Datascript re-wrote his ICFPC submission from Clojure to Rust and gained 17x speed increase [1]. This could be something to poll.

[1] https://mobile.twitter.com/nikitonsky/status/114850460921383...

There actually is a question in the survey, "What has been the biggest obstacle to using Clojure?", but it's not highlighted in the blog post.
It's hard to want to choose Clojure when it's hard to know where to start. I saw "CojureScript" followed by "ColjureCLR" and just blacked out... I'd like to learn a lisp and I hear clojure is the jam, but seeing that ecosystem exists, while flexible, makes it seem like 90% of it will be learning the tooling and not the language... It just makes me think "hmmm. I need the JVM, might as well use Java... at least it'll be predicatable straightforward, and EXTREMELY well documented, in it's convoluted-ness[1]"

Can someone please sell me, or assure me, otherwise?

[1] Which is also high... I can barely get a JVM project running these days with the plethora highly foreign of build tools, IDE dependencies/configurations, and language settings. Maybe that's just par for the course in 2020 on the JVM, with great power comes great complexit?

There are all sorts of bells and whistles you can choose when it comes to Clojure, but I would recommend you focus in one thing for a start, just plain Clojure with the JVM.

Download a Clojure jar [0], the following command opens the REPL:

    $ java -jar clojure-1.10.1.jar
... you can also run the file you are editing:

    $ java -jar clojure-1.10.1.jar file.clj
... that's it! You can go a long way just like that, the start up time of running scripts is not that bad.

Gradual improvements:

* Perhaps install a clojure package [1] instead of using the jar. The jar is nice to understand the main Clojure compiler is at its core just that, a Java program... but the package installed with brew or apt will probably (depending on your OS and how up to date the packages are) also give you a global `clojure` or `clj` command that you will see around in tutorials. Just makes it easier to follow the tutorials!

* Use rebel-readline [2]. Just follow the readme!. It gives you a nice coloured command line REPL with all sorts of cool features, but you don't need to make use of all of them at once. Take your time!

* Choose an editor with good integrations. Obvious choices: VSCode+Calva extension, IntelliJ+Cursive, or Emacs+Cider. The main thing about having a good integration is the instantaneous feedback of sending chunks of code to the REPL, although for a slow start you can do the same just copying and pasting code from the editor to the REPL!

About books: I read 3 or 4 different ones... most books I read were pretty good, some of them are available online for free! Confidence comes from writing lots of code mostly, though, not just reading. I'm not proficient enough yet that I remember the APIs yet so books help to gimme a cohesive roadmap of things to learn.

Suggested little "project": I also found this library [3] that is cool to play a bit with random things to produce some graphical output. It is a wrapper around Processing.

Good luck!

Caveat: there are many ways to do teh same thing. This comes from a focus on libraries over frameworks. Also, the whole JVM API is available to you so for a lot of things you are supposed to just use the Java APIs. Don't bother about wrappers or clojars for a start, just call Java from your clojure. Is fast, fun and easy! :-) Pick one way of doing things and do it for a while... even if it doesn't give you the "fullest of the performance" for any given task, it will be an OK vehicle for you to learn and get familiar with the ecosystem. Classical example: http servers.

0: https://repo1.maven.org/maven2/org/clojure/clojure/1.10.1/

1: https://clojure.org/guides/getting_started

2: https://github.com/bhauman/rebel-readline

3: http://quil.info/

You can't actually use the Clojure jar like this with java -jar as it has a couple of dependent libs (spec.alpha and core.specs.alpha). But getting started with the `clj` tool is just as easy.
My bad! I tested it my system and it worked, but I'm sure I have the jars in the classpath already because I had already installed Clojure through a packet manager.

So! Clojure 1.8 still works without dependencies for trying the jar [1]. Otherwise, I'd skip to installing 1.10 through the system installer.

1: https://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/

See my post above, just build the clojure jar yourself using the ant instructions, and it will be portable again.
You can if you build the clojure jar yourself. Just follow the ant part of the clojure README to generate your own jar. Then you have a super portable clojure jar again. https://github.com/clojure/clojure/
This is cool, though for lowering the barrier of entry downloading a single jar is great. If ppl is first coming to Clojure w/o too much knowledge of java, having to install Ant first, clone a repo and build it manually could be a bit daunting.
On macOS: brew install clojure

Linux can use brew as well, or just download an installer shell script and run it.

Windows can use an (alpha) installer for Powershell or use Scoop via this bucket https://github.com/littleli/scoop-clojure

That's for the official CLI that works with deps.edn files for dependencies.

You can also download Leiningen -- a single shell script (macOS/Linux) or batch script (Windows).

If you use brew/scoop, I don't think you even need a JVM installed as they will do that automatically.

My suggestion is mainly for people that want to "trim the fat" , have maximal control of things, or want to use this as basis for non-standard deployments. I just want to support the OP that you don't NEED to download all this tooling to get it to run on any computer. Once you have the jar, its very easy to put it on a friend's computer. You can even package up a JVM in there if you wanted too. While not up to date, I describe my motivations in dj.solo https://github.com/bmillare/dj.solo
This has been exactly my experience. Great language, but ended up spending far too much time fiddling with the tooling and trying to comprehend the interactions between Clojure and the Java ecosystem.
Isn't Clojure an extremely unpopular language (outside HN)? I mean, it's not even in the top 50 in TIOBE index.
TIOBE is garbage. It is primarily based on google search hits. Red Monk's ratings are based on github and stackoverflow (which Clojurists actually don't use much) and typically has Clojure around 25, which I think it is a defensible ranking. Best estimates of devs using Clojure are 20k-50k (based on multiple sources, some public, some private).
Wow, TIOBE has Object Pascal, Assembly, D, and PERL in the top 20. Also, MatLab over Objective-C. Meanwhile, Typescript is at 46, well below Julia, COBOL, Ada, and Rust (don't get me wrong, great language, but I'd be surprised if it was more widely adopted than Typescript).

Its method for ranking seems problematic.

> Isn't Clojure an extremely unpopular language

Are Haskell, Rust, F#, Elixir, OCaml, ReasonML, Elm, Purescript, Racket extremely unpopular?

Clojure today has more podcasts, books, conferences, jobs than any of these languages. But sure, it is a dying programming language. Just like Haskell has been "dying" for 30 years now and OCaml "died" multiple times in the past 24.

There are good reasons why they are still being used and why people get excited about them.

I studied Java at University and then worked with it for 15 years through various companies, finance mostly. I like the language but the opportunities and my use of it felt very stale in the end.

I switched to Clojure a decade ago, around the time I started working with distributed systems. The best move I have ever made. I love working with Clojure and I find a large benefit in my understanding of the JVM.

Recently I've built a front end (Clojurescript) and some lambda services (Clojurescript on Node) to complement my startup (Clojure, https://operatr.io - its a tool for Kafka). There's an advantage to using a single language/mindset through your entire stack.

I spoke at the last Conj (https://www.youtube.com/watch?v=MnvtPzEH-d8) about my experience, broadly speaking my top reason for loving Clojure is that I am much more effective in delivery today than I was a decade ago. I simply don't believe I could have built Operatr in Java/Javascript, YMMV.

In technical terms Clojure's data-orientation coupled with host-interop is much more important to me than it being a functional language or emacs/vim etc. Turns out I still use Intellij (with the Cursive plugin) and my work setup has changed very little.

It's a great tool, if you haven't tried it you should have a play - particularly if you work with Java.

>I love working with Clojure and I find a large benefit in my understanding of the JVM.

Reliance on the Java ecosystem has been the biggest issue for me in trying to use Clojure. I love many things about the language, but I have zero experience with Java or the JVM. A number of my attempts at using Clojure for a project have been hindered by my lack of understanding of the underlying runtime and the tools. In a way, it almost feels like Clojure simply isn't for me.

On the other hand, I've had much more luck with ClojureScript, which I'll happily use over JS any day, though the build system still occasionally mystifies me.

The only reliance you have is on libraries that are often battle tested, well engineered, and cover any project space. Quite different from some other ecosystems I won't mention.... of course YMMV.
I agree with this, Clojure being hosted means you have to understand the host decently enough. This is a downside and an upside since Java and JS are large, popular ecosystems. But in some cases I wish there was the option to just compile a binary. As for now, I can’t recommend the language to people who don’t already now Java and/or JS. (Maybe WASM/WASI will open this door at some point.)
There is now an option to compile a binary, it uses GraalVM native-image technology

We're growing a scripting ecosystem in Clojure now thanks to this, it's still relatively new

As a newcomer, I've made several native binaries for different operation systems

GraalVM does not solve the reliance on the underlying host (JVM, Java) problem.
Well that depends what you define the host problem to be

End users can certainly run Clojure programs natively without having the JVM installed on their machine

You can do that without Graal using jpackage. The only boon of Graal is native binaries and interop. But if you want to ship the JVM the user doesn't need it installed.
I wonder if native apps built with Graal or jpackage could be accepted at the Apple macOS and Windows app stores?
Graal probably. Apple seems to not like JITs so shipping the JVM might be out of the question.
And the 'problem' is not a problem at all.
Are you watching projects like Janet language? For me, JVM is a nonstarter in any capacity, but I welcome that PLT circles are learning from Clojure's design choices and that other lisps are increasingly feasible.

It's not clojure, but it's clojure-ish enough that it can be pleasantly productive for little scripting tasks and smaller problems.

Another language with a syntax similar to Clojure is the Hy language built on Python (I just released a book on Hy https://leanpub.com/hy-lisp-python so I admit positive bias for the language). I used to use Clojure a lot for two consulting customers and I need to try it again. I think the project libpython-clj https://github.com/clj-python/libpython-clj looks very interesting for those of us who like Lisp and need access to deep learning tools.
I can imagine to a degree, I have zero experience with Javascript and I found the practice of getting a Clojurescript REPL very complicated.

Once I was set up I quickly became effective, though I do tend to stay within the bounds of Cljs and avoid the host where I can.

Yeah CLJS REPLs are a pain point currently (if you use Cursive specifically) Emacs and Atom and some others are much easier, that said a lot of people start with the hot code reloading since that experience is really nice and works out the box for Shadow-cljs or Figwheel

Then eventually set up their REPLs, I know Cursive is working on this though and the nice thing there is you always have access to the "standard library" provided by the Google Closure compiler all of JS and then all of CLJS and all of npm and all of CLJS's libraries

For me, the browser has way more baggage as a runtime than Java ever could. I've only ever found working on top of the JVM a massive boon, and I don't feel at any point I've had to have a deep understanding of different garbage collectors etc. The most complicated thing I've ever needed to do is increase the maximum heap size. In exchange for that I get access to an enormous ecosystem of industrial strength code for free.
I'm curious to know, why Clojurescript on Node vs clojure on the JVM for this project?
Using the JVM on aws lambda isn't such a good fit due to startup time.
Every Java developer ever: "after >=10 years of java, I switched to ruby|python|js and I'm so much productive now!"

Also, surely your 25 years of experience have nothing to do with you being more productive now than 25 years ago.

People switch to Clojure from other languages, not just Java. I've seen plenty of former Java, Ruby, Python, C#, JS/TS, C++ and even Haskell devs who switched to Clojure and say - Clojure does feel more productive.
More productive than the day before they switched, not 25 years ago.
This is the point. I still work in Java occasionally but I'm much more effective delivering in Clojure today - with 10 years experience, than I am in Java which I used my entire career.

Same host environment, many of the same libraries, same developer. Different language, different mindset.

Fair warning to anyone picking up Clojure / ClojureScript: it can make you less productive by making your old tools insufferable.

It's like taking an automatic 2.5L turbo Subaru w/aircon for a spin and then getting back into your 1.3L Toyota Tazz - daily driving won't be as fun again for a while.

Lisp "ruined me" for a few years because after trying it I couldn't stand using anything that dit not have macros and Paredit. It's like the saying, "Beware of tasting freedom; it can make you psychologically unemployable."

For example, dealing with the abomination that is JSX when I could just write a pure ClojureScript function that returned Hiccup data structures that gets rendered to HTML. And you get isomorphism for free (one codebase on client and server).

I initially switched to Clojure for Datomic (the killer app for Clojure, IMO), but now I mainly write ClojureScript and use DataScript (datalog on the client) in every project.

Datomic really is a killer app in terms of its features, but it doesn’t seem to be targeted at solo/small teams with its pricing and licensing model.

Datascript looks interesting. I guess you get disk persistence with event sourcing?

If you are willing to go with AWS the cloud deployment model's pricing is much more palatable.
You can use Datomic for free for up to 2 peers right? That should be enough for a fair number of solo projects.
JUXT's Crux database[1] is worth looking at. It's open source and free. It is also an immutable, time-traveling, event-sourced database with a datalog query engine. Datomic is still more fully featured in a lot of ways, but Crux's concept of bitemporality is pretty interesting and something I've been wanting to explore deeper.

[1]: https://opencrux.com/

> Fair warning to anyone picking up Clojure / ClojureScript: it can make you less productive by making your old tools insufferable.

Surely there was an old lisp quote for this ? same goes with haskell / prolog I suppose

Haskell's kind of the winner here, in that people seem to take substantial pay cuts to work in it.

(I do not work in it.)

Hehe that's a fun thing to read.
The question for me is where do I find remote clojure jobs? Playing with it is all fine and all. But how about making it a full-time thing?

Most job boards have next to no entries and clojure boards are mostly US only.