ClojureScript is the most-used functional language that compiles to JavaScript
sekao.net
sekao.net
I say this after running the last command in the REPL - it's what I've been doing for the last 2 hours. I haven't looked at the browser since I started.
I switch to the browser and sure enough, the whole thing works perfectly.
This is the Clojure(script) experience - it's a different method of developing applications. Combined with the brilliant weirdness of the language itself, it sucks you into the REPL and persists even after you've finished coding.
The most suitable word for this experience is "hacking". You don't code your program, you hack it.
The only drawback of Clojure/Clojurescript is the high learning curve.
Maybe the 20 years of OO programming have really left a dent on my brain or maybe it was because of the young age of the ecosystem, or maybe because tooling wasn't quite there yet, but I found it quite a challenge, before I could write even basic programs.
Even now, after having spent months learning it, I still find it intimidating.
Oh and did I mention how much clearer it is to write C++ after learning Clojure ?
Pure functions, immutable data, data vs code.. just some of the concepts that help a lot when you bring them to an OO language.
For example I'll often write a function in a source file, evaluate it from there so it exists in the process, then call it from the REPL to test it works correctly.
When I launch the program, every temporaries made at the REPL are gone, but the source stays.
For instance, I use tmux/Vim/Vim Slime, which allows me to send code from the editor to the REPL (running in a separate tmux pane). This setup isn't as embedded or as fancy as some of the other options (e.g. Light Table). However, this setup doesn't force me to break my standard workflow and works with other languages which offer a repl or interactive console (e.g. Scheme/Racket, Ruby, Haskell, JS, etc.).
So with respect to the high learning-curve, a few questions:
1. Were there any non-obvious concepts that you wish you'd understood going in? i.e. anything I can do to make my learning-curve shallower than yours?
2. Can you recommend any resources for getting started?
Once the messages set in, any ClojureScript-specific tutorial will be a breeze.
Clojurescript can be hosted entirely in js; here's a repl: https://github.com/anmonteiro/lumo/
I've used 'the JVM argument' to justify putting the language aside for a year or so, but now I'm back and it doesn't seem to bother me as much.
Why would it do that every time one compiles one's project? Surely Clojure must keep a cached linkable byte-code/binary somewhere per version/OS/arch, as all modern languages seem to do?
http://dev.clojure.org/display/design/Improving+Clojure+Star...
I invested a lot of time in learning clojure, but Oracle concerns me enough that I'd rather not build my knowledge stack on them.
So I've stopped using clojure. I may look into clojure script again in the future, but it still feels like a kludgey experience to me. Inspite of the amazing efforts by David Nolan and the community.
[1]: https://developers.redhat.com/products/openjdk/overview/
1. In project.clj, add the nrepl port for figwheel: :figwheel { :nrepl-port 7002 }
2. Start figwheel with `lein figwheel` and open the page in the browser
4. In IntelliJ, Create a new Clojure REPL -> Remote, pick "Connect to server" and enter "localhost" and 7002 for port.
5. Start the REPL, it should connect to the figwheel repl, then type (cljs) and you should be in the ClojureScript repl.
6. Test that it works: (js/alert "Hello")
[0] https://cider.readthedocs.io/en/latest/up_and_running/#using...
> I switch to the browser and sure enough, the whole thing works perfectly.
This is the general workflow in a typed language as well (i.e. PureScript, Elm) - you write some code and then fix the type errors in the editor - only that instead of running a couple REPL queries and just assuming that your app works, you really do have some hard guarantees in all edge cases, like no crashes, no type mismatches, logical coherency.
Most of the time this then means that the "app works".
But I think another drawback of cljs is readability. It's super cool that everything is data and data structures, but it makes it harder to eyeball code, just takes longer to parse and understand how these data transformations actually map to side effects on the page.
IMHO well written OO code is easier to understand and reason about.
Second most used FP <> JS language would probably be Scala.js, which, as far as we know[1] doesn't yet have many companies publicly using it.
Take it all with a grain of salt, OP himself says, "ClojureScript has almost certainly become the industry's most-used functional language that compiles to JavaScript. Admittedly, this is like being the most popular person who can speak Klingon".
Translation: combined adoption of niche languages <> JS is still miniscule.
Sure, with Node.js on the server then Elm, Purescript, BuckleScript, etc. can do client-server, but they can't do so in the same language, seamlessly share code, etc. That's one of the selling points of one-language-to-rule-them-all (i.e. target js, wasm, native, clr, jvm, ...).
Saying that, looking at BuckleScript this weekend -- completely shocked that there's zero overhead wrt to generated file size; it's like typed Coffeescript a la OCaml, unbelievable (this from a dev using Scala/Scala.js in day job).
> [Javascript is] a multi-paradigm language, supporting object-oriented, imperative, and functional programming styles https://en.wikipedia.org/wiki/JavaScript
The author must have a very particular idea what "functional" means to include Clojure but not JS. That's fine, though it'd be enlightening if he shared it.
Functional languages emphasize immutability. Javascript does not do this. Clojure[script] does.
I'd argue a "pure" functional language is akin to trying to write a novel on a keyboard without an "e" key. Sure, you'll eventually stumble and write "Gadsby", but there are times when being able to cheat is useful in making your code more clear and concise. When I code stuff in C++ or C#, I keep my objects immutable most of the time because it's the easiest way to rationalize the various components that way, but at the same time, when I'm doing things like handling I/O, a pure functional style gets in the way.
Since functional programming is a programming paradigm, not a language, don't be surprised if many languages support it, just as many diverse languages support OO.
The language support generally thought necessary is first-class functions (and consequently concepts like higher-order functions). For example, Java < 8 and C# < 2.0 aren't usually considered functional.
If you think allowed mutability makes or breaks a functional language, then neither Clojure nor Clojurescript fit the definition.
Like, once you have
* first class functions that you can pass around * anonymous functions * closures over functions
you can get by. This is what enables you to create the usual higher-order function toolbox, all those nice functions that convert your code to long list of composable map/filter/reduce/zip/walk e.t.c.
I remember reading that python got here iteratively, i.e. you could pass around functions, but they needed to be defined top-level, then you had anonymous functions, but you needed to pass in variables from enclosing scope explicitly, and finally you had closures.
But I agree that fast, immutable datastructures make all of this much nicer. But not having them is not as much of a deal-breaker.
Similarily tail-call optimization. I used clojure at work while dealing with haskell on a school projects, and from that time on, I found "loop/recur" kinda ugly :-) NodeJS with --harmony actually supports it now.
Similarly, pattern matching. Don't you need to pull that as a lib in clojure as well? With destructuring this almost is a js feature.
So, I wouldn't loose much sleep over it anyway :)
> [It] treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.
Javascript certainly doesn't avoid changing state or mutable data, as its two core data structures, objects and arrays, are both mutable.
The lack of native persistent data structures means functional programs need to depend on libraries like ImmutableJS and Mori to fill in the gap, but in doing so they have to trade away language features like spread and destructuring that improve readability and minimize boilerplate, and take a hit to ease of debugging. I almost always pick up ImmutableJS or Mori for my JS projects these days despite these issues, so it's certainly not the end of the world, but whenever I work with them it's painfully clear that persistent data structures, and by extension functional programming, is a second class citizen in the context of the language.
The ecosystem issue is a much harder one to work around however. You can take every precaution to carefully craft your code to minimize side effects and manage state transitions, but there's only so much you can do if your components/visualization/networking library (mis)manages its own internal state. The situation has improved dramatically in the past few years with the advent of React/Redux, and we've experienced a functional programming renaissance with tons of great new libraries popping up that are amenable to functional paradigms, but we're only just starting to make a dent in the massive JS ecosystem, which is still overwhelmingly inadequate when it comes to dealing with mutable state and managing side effects.
All of these pain points become painfully obvious once you've worked with an ecosystem that has spawned from a functional-first language that is immutable-by-default and encourages being mindful of state and side effects (in my case, that language was Clojure and ClojureScript, but that's certainly not the only one).
The only efficient way to return a brand new database that is the same as the old database plus 1 new widget is via immutable data structures.
I'm no newbie to FP (IMHO) but this has me perplexed now.. is there a difference between mutable and "non-immutable" ones, or do you mean to say that JS has neither immutable nor mutables ones? ;)
What have you used to get up and running?
Also, its README is worth reading even if you won't use re-frame :)
Also, there are a bunch of languages with functional features which compile to JavaScript. I don't think ClojureScript is more popular than, say, TypeScript or Dart.
But sure, TypeScript appears to dwarf all other compile-to-JS languages in terms of actual usage.
I once ran a meetup with ClojureScript Koans and people loved it. I should hopefully add a few.
Whatever shortcomings of JavaScript these languages claim to solve are not worth the pain and suffering that this extra compilation step adds.
They all claim to compile really fast, yet whenever I have worked on a project which uses a compile-to-js language, they always seem to end up taking 10 to 30 seconds to compile each time and this slows down debugging significantly.
I use typescript and have it watching my files. Compilation (or transpilation, whatever you want to call it) time isn't an issue. I could see it being quite a hindrance if I had to run tsc on my entire project every time I changed one line, I don't know if this is the case with clojurescript, but it would be a downside for sure.
Not only don't you need to wait for recompilation, you don't even have to reload the page to see the changes. Everything happens interactively as you're writing the code.
[1] https://github.com/AgentME/browserify-hmr/, a Browserify plugin made by me.
You may also be interested in my experiences with it http://yawar.blogspot.ca/2017/01/bucklescript-significant-ne...
Oh yeah, that's huge, at least the time to sip half a glass, that's scandalous. Hmm... you're kidding, right? How can it be a problem in absolute value, and furthermore how can it be a problem in relative value? That time should be absolutely negligible vs the design, the thinking, the typing, the thinking again, etc.
> and this slows down debugging significantly.
There is also the option to think about what you program instead of proceeding by trial and error.
I don't want "a project of a certain size" to be handled through trial and error. And yet, according to the pitiful results and condition of current software, especially shitty web apps, that has to be representative of the current model of development.
"Should I put more space here? Is the border too thick? Let's see".
"Oops! I know why it's failing. I'm quickly going to fix the order of the arguments".
It's great if you can do these things in 3-10 seconds instead of minutes. Not everybody is designing airplane control software.
Edit: Why the downvotes?