Hacker News new | ask | show | jobs
by deergomoo 1890 days ago
Apologies if this is too off-topic, but I'm currently trying to decide between Elm and ClojureScript to get started with FP. Can anyone weigh in with recommendations?

The points this article makes like strong typing pull me towards Elm, but people talk about understanding Lisps as a nirvana-like state of enlightenment, which pulls me towards Cljs

9 comments

If you're writing modern Javascript, you're halfway to Lisp nirvana already. Lisp was a huge mind-expander for people like me coming from BASIC, Pascal, and C++. Building programs out of functions was an entirely new way of thinking: writing functions that returned functions, creating abstractions that were parameterized by functions, etc. That is already normal to you.

The other big Lisp nirvana thing is macros, and let's face it, they're cool, but the best way to use macros is sparingly, especially when you're working with other people, so they don't make as fundamental a difference to the way you code as you would expect. At least in my experience; YMMV.

If you're coming from modern Javascript and looking for a big idea that will change how you go about the job of programming, I think working with a static type system will be a bigger eye-opener.

Disclaimer: I'm now fully in the Elm and strong static typing camp, so... I'm biased.

My anecdote is that I wrote a backend Slack bot in Clojure (not ClojureScript) - the experience was great when writing it. But three months later I had to go fix something in this codebase and by then I didn't remember as much about it. And getting back "up to date" was so hard for me that I burned out on that project and rewrote it in Elm. (Yes you can write headless apps running on Node in Elm.)

The development experiences might be similar (Clojure might make you feel slightly smarter and cooler), but the maintainability "3 months after" was much better after the rewrite to Elm, since the compiler won't let you even run your app unless everything checks out (compared to Clojure which will just happily raise a runtime exception). And you have type annotations as a form of documentation for your future self.

I think the bigger issue between Elm and Clojurescript is that while Clojurescript is a language, Elm really is a total toolkit for web application development. Elm has its own virtual DOM, various types for interacting with the browser, and is very possesive of the DOM making pulling in non-Elm code challenging.

Meanwhile writing a web app with Clojurescript will require making more choices around libraries you want to pull in, although you can always just go with re-frame which is awesome.

As far as more theoretical learning, I'd go with Clojurescript. Clojurescript is a real lisp with all the fun stuff you can do there. Elm is an intentionally gimped ML variant made so to make it more palatable to the Javascript developer community. If your goal is to learn about typed FP while running in the browser, you'd be better off with ReasonML.

If OP is a beginner, I think Elm's integrated approach (less fighting with build tools), pretty good docs, and larger ecosystem will be easier to learn than the more powerful, less united, and less documented ReasonML.
I've been doing a bit more elm (some at work) and I've tried to get into Reason from time. I always aborted on the first day. Last time I tried to learn ReactReason in december, I think their VSCode tooling wasn't working at all.
Elm fanboy here. Although always "hobby projects", I have worked in both ClojureScript and Elm. I finished a project in Elm that I would not dare to start in ClojureScript.

I learned way more from Elm in terms of frontend architecture ( I am employed as frontender) then from any other framework/ language.

If you want to get started quickly and don't want to stress about how to do something than Elm. From my personal subjectiv experience I never felt such joy to build a web-based frontend. Because of its type system and the model it enforces on how to do things. Also in my experience when the code compiled it really just worked (besides logic errors the compiler can't catch). Refactoring was also a breeze with the help of the compiler. Another big plus are the error messages procuded by the compiler which are the best i've seen so far. So overall i found it to be a really good beginner experience.

Whereas CLJS is at the other end. A tool for experienced developers who know what they want and how to do it. As it requires you to make a lot of choices. That Elm, for most parts, already made for you.

Elm would be a great fit for that. The language, IMO, manages to be both simple and powerful. And the Elm compiler is a joy to use (great error messages and very fast). I haven't used ClojureScript though, so I can't offer any comparison.
I recommend trying both to see which one you like the most. If memory serves, Elm's architecture is inspired by the re-frame library for ClojureScript.
I worked with Elm for 2 (or maybe 3?) years, and with Clojurescript for another 2. I recently had to decide on which of the two I would use on my next project, and it was definitely not an easy decision. Ultimately, I went with Clojurescript.

Main Clojurescript pro was re-frame[0]. Re-frame makes state handling easy and, especially importantly for performance-sensitive projects, it entirely removes the (rather common) problem of re-renders with the way its subscriptions are handled. This, plus the ability to have your entire stack in a single (amazing) language, were the tipping points to me.

While you can't achieve the same level of compile-time safety in Clojurescript, you can apply "state checks" (with Spec or any custom validation mechanism) any time your state changes. And with re-frame, it is extremely clear when your state changes, therefore you can block any invalid state from being saved and catching it as soon as it happens. Again, not the same kind of safety you have with Elm, but to me it's a good-enough trade-off.

And that's exactly what I do with my code: every time my state changes, I run a validation check on the keys that are about to change. If their value is deemed invalid, an error popup (identical to old Windows XP error popups, because why not) will appear, stating what the invalid state is and what it should be like instead, as well as which event led to this state in the first place. This check is so fast I don't even need to disable it in the production build (but instead of a popup we get a notification that an invalid state error happened).

In fact, there's this (non-mainstream) argument that runtime checks bring even more power over typing: https://www.youtube.com/watch?v=nqY4nUMfus8

TL;DR: Not an easy decision, but the truth is whichever one you pick, it will be a great choice.

[0] - https://github.com/day8/re-frame/

I made the jump from JS to CLJS and loved it, but in the end I like types and ML more than I like Lisp.

Do both, but do Lisp first.