I'd still rather use ClojureScript, though.
I'd still rather use ClojureScript, though.
I came from low level language background but my "fun programming" went from Lisps to MLs and now I have difficulties going back to Lisps for projects. Always wanted to like Clojure but never had a need for JVM in anything I worked on.
The homoiconicity of Lisps allow me to think less about syntax. (function <args...>). And reading code is easier, since I see the operations first. Adding more advanced features (via macros) can give you lovely function chaining - threading, piping, etc.
Immutability in Clojure is also good for me because it allows me to learn and forget about functions. Black boxes are great things when you can trust that they are pure functions; just compose bigger black boxes and so on.
I don't do a lot of Clojure these days, but when I was using it professionally I could basically forget about JVM; JDBC was about the only time I interop-ed with Java. If you need some of the good things that JVM offers, great; if not, it's just a hosting environment. Same with Elixir and BEAM (although JVM and BEAM are very different and tailored for different problem sets).
But on topic, given a choice between ReasonML and JavaScript, it seems to me that ReasonML is more thought out, cleaner, safer, and a step in the right direction.
Dynamically typed languages force me to keep type information in my head, and that's just not a good use of my brain when the compiler can be so much better than me at this.
Compared to toys like Perl, Ruby, Python, etc., proper dynamic languages (Lisp, Smalltalk) have state of the art debuggers, browsing and discoverability tools and let you backtrack, experiment and tweak your program in an iterative fashion. They are indeed "little brain" friendly and the development experience matches or surpasses those of compilers and classical IDEs.
I am so much more productive in LispWorks than, say, IntelliJ+Java it isn't even funny.
- Because of "true" REPL. Having to be able to evaluate any expression without any ceremony, right from your IDE, with one or a couple of keystrokes is remarkably liberating. No language I have tried gives me that enormous boost when prototyping things. Even refactoring existing code is much faster, because of the tightened feedback loop. Only Smalltalk comes close enough, sadly, Smalltalk has been dormant in years, and I don't think it ever comes back as a pragmatic choice to build a business upon. Whenever anyone retorts "Python has REPL, Ruby too, etc." - it is just sad to see their ignorance. One has to give a heartfelt try to understand what makes Lisp REPL so unique.
- Because it is currently probably the best PL for building web-apps. You get real code-reuse, which even in NodeJS with JS/TS turned out to be an unfulfilled promise. You cannot merely share say data validation logic between back-end and front-end, even in NodeJS, let aside other languages. In Clojure, this turned out to be possible, even though you essentially might be running things on two completely different platforms - JVM and the browser.
- Because you have access to tons of libraries. Java and Javascript interop from Clojure and Clojurescript is lovely. Why re-invent the wheel if someone has already done it?
- Because of the fantastic community of genuinely inspiring, smart, and extremely friendly people. When you work with Clojure/Clojurescript, you always feel a step ahead of the crowd [working in other, more popular PLs]. So many things in different languages got inspiration from Clojure: destructuring, immutability, state management (redux, Elm), React hooks, etc. etc. And at the same time, Clojurists never feel shy and actively "borrow" good things from other languages, libraries, and tools. Clojure community of active members has probably fewer people than work for Google, but they generate and enhance so many awesome and cool ideas.
My summary is: the extra burdens - tight coupling, code verbosity, custom type propagation for dealing with sparse or varying data - are just not worth the cost.
Also, I don't think there's much real evidence that static typing prevents production bugs. If you're doing decent testing, you'll catch those problems. And if your solution is fewer LOC and easier to reason about, you're more likely to not make type mistakes.
One issue I have with Clojure is when I have to work with nested datatypes to perform transformations. It's just too hard to keep the shape of that data in your head. Types help with that.
Another important thing is modelling business domains with types. By this I really just mean record and variant types and not some advanced type-fu. It really helps seeing what kind of data your application manages.
And in Ruby or Java, I have the same problem with objects.
No matter what your method of interaction, keeping up with levels of abstraction is hard.
Out of so many "excuses" to dislike Clojure I've heard over the years, the first time I see something like this, and this sounds wrong for a few reasons. Dealing with nested transformations is not harder or easier in Clojure, it is just different, due to immutable data structures.
Besides, if you need to deal with deeply nested data perhaps it has to be broken down into smaller pieces. Maps are extremely composable in Clojure.
There are libraries that can help you with transformations, you can "walk" the structure, you can use zippers, you can use Specter (a library that I haven't find a use for in over three years of writing Clojure).
Modeling business domains with types is a valid point though. However, I find exactly that is the reason why using Clojure for building real business apps is so much simpler and faster. You are not restricted by the boundaries of whatever type system you use. You don't get stuck in analysis paralysis trying to prototype things in an overly complex type system. At the same time you don't necessarily have to throw the types away. Type systems do help and absolutely have certain benefits, etc. And Clojure has a pretty nice one called Clojure.Spec. In Spec you can for example conform that your function returns specific shape of data. You can use specs to validate inputs, produce human readable error-messages, generate fake data and use it for example for property-based testing. Specs can be shared between different systems, between front-end and back-end, etc.