Clojure's immutable data structures (lists, vectors, maps and sets) are actually not copy on write, they're based on red-black trees such that when you "mutate" the value, a new one is created that shares everything but the mutated part with the original.
Clojure is amazing and i can't recommend it enough. I wish more people looked past the unfamiliar syntax and understood why it exists and how it makes you achieve more with simpler code.
I think Clojure will be fine. It is slowly and steadily growing. I honestly think it has reached well beyond the point where it can fade away. People always bring Common Lisp as an example and mention so-called "Lisp curse", etc. but if you follow and analyze the history of PLs - you'd probably realize - Clojure is a natural next evolutionary step of Lisp.
The industry desperately needs languages like Clojure and Haskell. Haskell being somewhat more "academic" and a bit "impractical" (I should emphasize the double quotes: Haskell in the right hands can be extremely, dangerously practical) never going to reach the status of a mainstream language, whereas Clojure just might. Realistically, it probably won't ever become top ten in TIOBE (or whatever similar) index, and that is totally okay. But it is pretty good already, and it is arguably better than Python and Ruby, Java, Javascript, Go, C#, etc. Clojure is Haskell's "worse is better".
And look: it already has more conferences and meetups (more than Elixir, Elm, OCaml, Haskell, Groovy, maybe even Scala) around the world (almost every European country now has its own seasonal Clojure conf.), it has over a dozen of books (and more coming), more podcasts. Clojure is a niche, but it is slowly become more popular.
To nitpick a little, Clojure maps are hash array mapped tries and vectors are trees with a highish radix and some push/shift optimization. As you said, they are collections with value semantics which is pretty great.
I'm pretty sold on Clojure's value, I've read up on its structure/syntax, but generally struggle with learning the standard lib and trying to read/write actual code. Any resources you can recommend for gradually ramping up, and/or "lightbulb moments" for a dev steeped in C-like languages?
One extremely useful resource is the Clojure Cheatsheet [1]. It organizes the standard library by all kinds of uses (data types, use cases, etc). It then links to the documentation of that function in Clojure.org, which often have examples of the function's use.
Likewise, each function page (if you scroll down) has a "See Also" which lists similar functions, which helps discover other functions in the standard lib.
Beyond the Standard Library, I find the Luminus Project [2] an excellent source of real-world code and documents for problems around web development. Further along these lines is the Clojure Cookbook [3] as well.
> "lightbulb moments" for a dev steeped in C-like languages?
I'm from C++, so I feel what you mean when moving from Imperative to Functional. I have two insights that helped me:
* Despite the huge type systems, languages like C have "Raw Memory" as the universal data structure. Think about pointer magic or the `union` type. Clojure does something similar; Despite the different data structures, the universal structure is `seq` which allows iteration over a data structure in the same way pointers iterate over any memory.
* Clojure's immutable data structures eliminate the Pass-By-Reference and Pass-By-Value dichotomy. As such, you aren't so much (with functions) altering memory as transforming data. It feels much more like math (especially Linear Algebra) where you are transforming data. Seeing my code as a series of transforms greatly helps my understanding of a piece of Clojure code.
The main example I work through is in JavaScript so that Clojure's syntax doesn't get in the way (I love s-expressions, but they're not the point of the talk).
Came across this talk a few weeks ago and I have to say this is one of the best pragmatic talks comparing non-FP vs. FP paradigms I've ever seen. I really like your example problem, how you explore state and mutation in the different paradigms, and how you refactor step-by-step towards a functional design. Thank you!
It seems to me what you’re struggling with is functional programming (the paradigm) instead of Clojure (the language or grammar) itself. This is pretty common for people who are used to the C-like languages. I strongly recommend reading “Clojure for the Brave and True” [1] (especially, Part 2) to anyone who is getting started on either functional programming and/or Clojure.
Having written C++ for 25 years, I found it very enjoyable to write small toy client-side web apps with clojurescript, figwheel and reagent. Reagent's Hiccup-like syntax for html is lightweight and gets you interactive stuff on screen quickly with hot reloading. Iterating quickly helps me learn, and getting dynamic graphics on screen provides that dopamine drip feed I need to stay motivated.
As someone who came from a similar background, the ice broke when I went from trying to write code the C way- in whole files, running the nascent program from the command line, struggling with compiler errors, adding printlns for debugging- to working at the repl. The repl is the whole thing.
Outside of standard recommended resources like the ones offered here [0], I found that doing the problems on 4clojure.com and then comparing with the answers of top users was helpful for experiencing some of those kind of lightbulb moments in Clojure.
I second this. Struggle with each problem and then view other answers to see how elegantly they solved the same problems. This worked wonders for me as well.
https://clojuredocs.org/ has been helpful, especially the examples, and the direct links to the code. Like working with libraries in any other language, if you have trouble understanding how something is working, reading the implementation is often your best recourse.
Using let can also be a decent crutch, if you're just not used to doing things with functional composition and (occasional) macros.
> I wish more people looked past the unfamiliar syntax
I truly doubt many professional devs are put off by the syntax. This is the least of the hurdles facing any (post-beginner) programmer learning a new language. It wouldn't even make it to the bottom of my list of criteria.
But also unfamiliarity in general is a hurdle. Clojure is unfamiliar in a multitude of ways and it takes some effort to realize how all these things Clojure is different in actually have great synergies.
Yes no doubt unfamiliarity (beyond the syntax trivia) is of course a barrier. How much of one it is depends on many things. The closer someone is to the 'curious' end of the pragmatic <-> curious learning spectrum, the less of a problem it is (indeed it might be an attractant).
Amazing how they just write a flat: "at least 30%" increase in productivity. Based on what exactly? How did they even measure that? I don't want to talk these slides down, especially since I think that a lot of use cases might benefit from something like clojure but sources would be nice to read up.
If you are referring to the "30% increase in productivity from REPL driven development", it could be he means not having to recompile after each change, so not having your workflow interrupted.
I find Python in the REPL to be great, but I think Common Lisp with Slime and maybe Clojure with Cider take it to a new level. You can write your code and when it errors out it drops you into the REPL where you can update the code incrementally while it is running.
If Python gets me X% increase, Lisp and Smalltalk (and maybe Forth) get you some X% + Y%. The parent comment is right that 30% is probably a back-of-the-envelope calculation and not a rigorous one.
I'm only a novice/superficial language geek, so I can't tell you why Lisp and Smalltalk can do that though. Extreme late binding? Hopefully someone more educated can reply.
Python in a REPL isn't really possible because you can't reload modules. It's OK if you're working on just one module but as soon as that's not true it's just not possible. And if you use relative imports you can't even do that.
I'd love to know if anyone has a way to get it to work because I really miss REPL based development from my common lisp and Clojure days.
That's part of it. That resulted in any given code change in a method usually requiring the recompilation of just one method. Much of the Smalltalk class library was fairly stateless-ish, so you could unwind the top one or two stack frames and restart about 90% of the time.
Other lisps with a repl might fall into the same ballpark, but offerings like the ruby and node.js repls are pretty inadequate by comparison. I haven’t used the python repl in a long time so I can’t comment there. In general I’d say that one of clojure’s strengths is the REPL+Editor integration that’s pretty common among all major editors supporting the language.
REPL + Editor integration is hardly language-specific, right? Most of the devs and analysts I can think of have some kind of REPL feature enabled in their editors and languages of choice, whatever they might be.
PyCharm offers similar functionality of sending code from the editor to the REPL. The biggest difference between Python and Clojure is that everything is an expression in Clojure, meaning you can send much smaller chunks (assuming vars are defined) to the REPL. With Python, you tend to have to send much larger chunks, which diminishes the utility for me to the point where I just don't bother.
Actually looks pretty simple and straightforward. There is a healthy choice of different editors and IDEs for Clojure right now, thanks to building on common foundations of https://github.com/clojure/tools.nrepl
I have never really understood what people get from these slides, but my while my experience with clojure is extremely limited I can say that I found it to be rather interesting but hard.
I could not grasp several error messages, took me a long time to write something to a database and it didn't really feel at all natural to me. But I guess you'll have to get used to the functional nature, but I don't believe all the hype about functional programming in general.
If it was so effective as people seem to claim, I am sure everybody would use clojure. My experience is rather the reverse, it is harder and takes a long time to develop in. Maybe it's more predictable and is better software with less bugs in the long run, but I wouldn't really know since I lack the experience.
A lot of programming languages today, like javascript, already has functional stuff within it. I get the appeal for it, but I'm not sure it's the best tool for every job or even most stuff.
If anyone is willing to post a youtube-talk or something that can convince me of otherwise, please feel free.
> A lot of programming languages today, like javascript, already has functional stuff within it
Yeah, but there's more to it than just that. You can find bits and pieces of good things in Clojure that influenced other languages, but in Clojure, they just feel right. Take, for example, immutable data-structures - there were many attempts to implement them for different languages, but somehow the way how they work in Clojure just feels subjectively better. Or the REPL. Of course, you'd say: Javascript has a REPL, Python has one, etc. But if you dig deeper, you'd find out that Clojure's REPL is somewhat better (it is hard to explain, one has to experience what makes it better). Standard library: Javascript is like a complete meth-head here - there's folktale, crocks, sanctuary, ramda, fantasyland, lodash, lodash-fp, immutable.js, etc. and you know, sometimes "more" is not necessarily "better"; Python's praised batteries can also be pretty frustrating. Whereas Clojure's standard library somehow feels much nicer and has a minimum amount of surprises. Stability of the language is almost legendary. Migrating a project from one version of Clojure to another won't cost you your leg.
Yes, Clojure is not a silver bullet (there's no such thing as "the best general purpose PL"), but it's specifically designed to minimize the frustration. And if you felt different, you probably haven't had enough exposure to it.
> If it was so effective as people seem to claim, I am sure everybody would use clojure.
I don't think this is even remotely true. As much as everyone in this industry wants to believe it's fast paced and fast moving / evolving, it's hellishly slow in picking up on good ideas and will waste an exorbitant amount of time on bad ideas...
Cool / Hip seems to be valued more than quality when it comes to languages / frameworks while the actually useful slowly, painfully slowly, trickles down.
I was around at the dawn of personal home computing and for the commercialization of internet technology so I have seen each of these come and go. Though they are not the cool kids anymore, the sheer volume of code keeps them around, and given that people have those skill-sets, new code gets produced in them.
Java was certainly the fad dejure in it's time, OO was the craze and Java had just been dumped out on the internet, by Sun, for free. In a time when a good portion of compilers costed money (especially if you where not on an Intel based PC), you could learn Java for the price of an internet connection.
c# was the cool kid if you where a Windows developer, Microsoft was looking to update their aging development stack and give themselves hardware portability, so they basically created the JVM for windows in the form of .NET . To ensure that people switched over they kicked the legs out of VB6 and pretty much forced everyone to the new dev stack. They offered a host of language that you could use to write windows apps, but they conformed all of them to the OO style that was popular at the time. With that said, VB.NET did not look like VB6 it looked a whole lot more like C# with VB syntax. So given that developers had to pretty much learn a new language even if it had familiar syntax most opted to just go ahead and learn c# as Microsoft was pimping c#.
Python is the odd ball in your list as it kind of languished for a while. It was not obscure but it was more like Ruby, it had it's devotees but was rather flat, not obscure just flat. That being said, it did have it's cool kid, day in the sun and that was when Google started using it heavily. The AI winter really killed LISP as "the" AI language and there really was no heir apparent, that is until (IIRC) Google started producing some of their machine learning tech and they implemented it in Python. This instantly made Python the cool kid and people started adopting it. My opinion is that Google felt they where too heavily invested in Java and thus needed to diversify into another language. At the time there where not a lot of options that had the combination of mature enough/without legacy clutter/availability of developers, to make the cut, that is why I think Python made the short list.
TLDR: the GP poster is right, popularity and trends have more to do with language adoption than technical merit does.
The fact that Clojure runs on JVM turns me off. I find that Elixir is very similar to Coljure, with a runtime that better supports immutability and concurrency.
Why does it matter to you? I mean, I know why I find it to be a positive: implementing a runtime is a vast and complex task, and doing it well is way too expensive for most projects (see for example the problems Python has had over the years with the global interpreter lock).
If you can use a runtime with gazillions of man-hours invested into making it better, and get easy access to bazillions of native libraries, why not?
While I agree with you that the JVM is great, I think most people that don't like it really just hate Oracle. It's not really a technical argument as much as it is philosophical. I don't really care either way, but I can see why people would mistrust Oracle knowing their history.
I understand the sentiment, Oracle is a terrible company and I don't like it either. But at this point we have the OpenJDK and you can use the JVM without caring about Oracle at all.
I switched to openJDK implementations after JDK 8 and lately that seems to be the way the entire community is going, due to Oracle’s new licensing restrictions.
> If you can use a runtime with gazillions of man-hours invested into making it better, and get easy access to bazillions of native libraries, why not?
As a Clojure user, I've only fairly recently moved from "the JVM is a boat-anchor on this design" to "the JVM is not an advantage, but it's not so terrible, either". So I'll answer.
> a runtime with gazillions of man-hours invested into making it better,
"Man-hours" are such a non-measure of productivity that the classic software engineering book in our industry has a title that declares them a "myth".
The JVM turns out to work fine for functional languages like Clojure, but from my perspective, there's no inherent reason it necessarily should. There's a huge impedance mismatch, as Clojure is not much like Java, and the priorities are completely different.
Bragging that some C program has had a gazillion people work on it means either it has a gazillion special cases (not an advantage), or it has a gazillion bugs fixed (most of which were probably caused by using a low-level unsafe language like C in the first place). Yay but ouch.
(Implementing a new programming language is also typically a vast and complex task, but Clojure has an impressively small number of contributors. When you think through the design first and focus on simplicity, you don't need a gazillion special cases.)
Coming from the Common Lisp world, there's gobs of pure-Lisp programs and libraries I've used which are absolutely a joy to work with, at every level. They don't need many contributors because the code is drastically shorter and simpler. There's lots of Lisp libraries with only a dozen commits, which haven't been touched in years, and a version number way less than 1.0, which work great. That's all they need.
> and get easy access to bazillions of native libraries,
I can see why these can be important when bootstrapping a new language environment, but in practice, beyond version 1.0, I really don't care about them at all. The interfaces I use from Clojure tend to be "return a function", or even "return a function which returns a function". No Java library is designed like this. They're designed around mutable classes, which makes them pretty awkward to use from a functional language. I'll go find a 100-line native Clojure library instead, and by now, there's 100-line native Clojure libraries for almost everything I need.
For another example, the numeric tower is part of the core of Common Lisp, so it's usable from anywhere. BigInteger is a library in Java, and Java still doesn't seem to have rational or complex types, so Clojure does the best it can, but anything beyond fixnum arithmetic is basically opt-in, and almost no libraries use it.
Debugging is even worse, because while there are a million google hits for "java library X", and a thousand hits for "lisp library Y", there's often almost no hits for "java library X with clojure". I have to mentally translate the Java X solutions into Clojure, and figure out any JVM/Clojure interop issues myself from first principles.
That said, Clojure overall works great in practice, and for the most part you can ignore the JVM and its issues. But any time I'm forced to become aware that the JVM exists, my life ends up being worse than the equivalent scenario in the turtles-all-the-way-down world of other Lisps.
You mentioned Common Lisp: it's a good example. I found bugs and limitations in CL runtimes and was several times in a situation where it was clear that I was the "only user". I do not want to be in that situation.
BTW, CL people often say that one should get a paid Lisp because of support. I did (AllegroCL) — and Franz people were really nice, but couldn't find the problem, and I couldn't dedicate the time to hunting it down and providing debugging information. Support doesn't mean that your bugs get fixed.
The JVM is not perfect, but its usage scale matters and means that in general, you are not likely to hit a JVM bug.
When people complain about JVM, very often it turns out that they hate the first letter in it. I felt the same, for very long time I ignored Clojure because I hated "Java" part of JVM. It turns out - JVM in fact is a pretty solid piece of tech. And not once I had to deal with Java code since I started writing Clojure. Don't hate JVM because you don't like Java. Bashing on Java might be well reasoned, but hating JVM (most of the time) is completely baseless.
If you just hate the JVM, Clojure was designed in such a way that it could be hosted on many VMs which is nice. As others have pointed out, it can run on BEAM VM or even V8 with Clojurescript I believe.
I've only just started looking at Clojure and I've been a little leery about the JVM as well (Windows/.Net guy). However, my experience so far has been pretty positive, and it's given me a reason to get more familiar with Emacs.
Additionally, there's a CLR version of Clojure as well [0] and I'm surprised that doesn't pop up very frequently. It seems to have a fairly active community around it as well [1]. I haven't looked into it yet, but I intend to once I'm more familiar with the JVM version.
I feel the CLR version doesn't get as much love, because it doesn't really bring much over the JVM. It's a pretty comparable all around VM, with pretty much the same trade offs and use cases. I think that's part of it. And since the JVM one is always getting features first and has a more active community, there's little reason to try out the CLR one.
That said, some do, and the maintainers are active, so I'm sure it works well if you had reason too.
Elixir and Clojure are much more different than they are alike. Having used both on projects, I found Clojure to be much faster to code with. But if you want all the great features that Erlang/BEAM provide, then Elixir is great.
There are alternative methodologies and languages that are similar to BEAM and Clojure otoh. Perhaps not comparable to BEAM when it comes to concurrency. Racket + ZeroMQ for those kind of problems, immutability and concurrency, is a very interesting combo though.
Sidenote: You could run on Javascript runtimes with ClojureScript, but given your statement, I don't believe that is interesting to you :)
I'm curious about VM support for immutability. I think it's a really interesting idea whether low level runtime support can significantly enhance performance of immutable data structures - is that what you're suggesting? Would you be willing to expand on it?
(My perspective: I am turned off by any language that doesn't have a JVM implementation because I have so much knowledge and trust of that runtime. But I have to acknowledge, byte-code level support for immutability is thin to non-existent).
How is Elixir similar to Clojure? Their syntaxes are nothing alike, their core principles are not the same, not sure I follow.
As for the JVM, I would be curious to know why it's a turn off. It has been worked on for decades and powers mission critical systems everywhere. Unless you are doing something where the size of the VM matters, or where GC as implemented in the JVM is a non-starter I'm not sure why it matters.
They have a lot in common. They are both fringe languages that compile to run on more popular established VMs, both with strong support for meta programming, both encouraging a functional programming approach, and both employed to tackle roughly the same kinds of projects. The kind of people that are attracted to one are often also interested in the other. I think it's perfectly reasonable to draw comparisons.
Too many people conflate clojure with high paying salaries. It's not clojure that is earning the salary... it's the kind of engineer who might practice something like clojure that is desirable.
I think the reason why Clojure (alongside with F#) is the most paid language (according to StackOverflow and State of JS surveys) because more and more FinTech companies are discovering that the language is exceptionally well suited for manipulating financial data (and not just that). Another reason is: like the one you've mentioned: Clojure mainly attracts more experienced, "grumpy" developers, those who have seen things and tried different ways and become almost apathetic and burned out from (over and over again) building and maintaining projects that despite all the efforts almost always spiral into big, unmaintainable clusterfucks.
Clojure is amazing and i can't recommend it enough. I wish more people looked past the unfamiliar syntax and understood why it exists and how it makes you achieve more with simpler code.