Its just another hard to debug compiles to js language.
I get you can share some code between server and client... but we've used it in production and now we're getting rid of it; there just wasn't a compelling reason to keep it over es6.
Its just another hard to debug compiles to js language.
I get you can share some code between server and client... but we've used it in production and now we're getting rid of it; there just wasn't a compelling reason to keep it over es6.
- hiccup syntax / sexps are trees analogous to the HTML you're constantly generating, and first-class supported data structures supported by the language which need no pre-compilation/transformation step, unlike JSX
- syntax is a good 20-30% less verbose than JS (yes, even ES6), especially when the core lib is taken into account (things like partition, zipmap, threading macros)
- one extremely battle-tested dependency resolution story, not named NPM - it just works
- incredible development tooling innovation, best of class for frontend web development
- the sequence abstraction and dozens of functions that operate on it, rather than Object.assign, Array.map, etc
- best-of-breed dead code elimination via Google Closure Compiler, meaning much of third party libraries and development-specific code ends up weighing less / nothing in production builds
- sets and set operations built in, along with tree walking, diffing and string utility libraries, included with the distribution
- no more defensive copying, thanks to immutability everywhere
This alone is worth all of it.
It has many advantages over those tools imo - but its dependency resolution model isn't one of them.
JSX works fine, looks like HTML, and Cljs needs precompilation anyways. Sexps being a pure representation of HTML trees has absolutely zero impact on productivity.
I use Closure Compiler, hot reloading and native Sets with regular ES6. I agree that immutability is a must and JS immutable libraries are just not ergonomic. If at least JS had operator overloading...
I love Clojure, but it just doesn't click for me in the frontend.
>> there just wasn't a compelling reason to keep it over es6 <<
How about these reasons:
- much simpler language - core.async channels/ no callback hell, easier to read async code - persistent data structures - great sequence abstraction - live code reloading - vibrant community - improved tooling - macros - transit
Given that it all compiles down to JS before execution, I'm not sure I agree. With Java, you're going to bytecode operations which (imo) allows for a simpler language than compiled to.
>> - core.async channels/ no callback hell, easier to read async code
I agree, callback hell sucks. I'm not sure that core.async is a huge win over promises, but this is an area that JS is quite horrible.
>> - persistent data structures
>> - great sequence abstraction
I'm not sure I see the benefits of clj's sequence abstraction over js. You get destructuring and sequence comprehension in es6, although clj's recur/callstack fix is quite nice.
>> - live code reloading - vibrant community - improved tooling -
I'm pretty sure all of these are better in JS than CLJs.
>> macros - transit
Macros are the old LISP fallback, but seem very counter to any argument of 'simplicity,' I very rarely find need for macros in the front and Clojure's design philosophy generally favors not using them (Data > Functions > Macros)
I do like CLJ and CLJS is interesting, but the only reason I really reach for CLJS is if I am feeling like writing something in om.next.
Most likely, they meant "simple" more in the syntactical sense than in the sense of language abstraction level.
> Macros are the old LISP fallback, but seem very counter to any argument of 'simplicity'
Macros is just transformation over a data structure, albeit a data structure that is interpreted as code later on. It shouldn't add more complexity than other forms of data transformation.
> I very rarely find need for macros in the front…
Neither do I, but I'm glad they exist. Core.async is built with macros, for example. They are part of what makes it possible to have core.async as a library rather than having to build it into the language.
Outside of the Clojure world this would be a reasonable interpretation. However, if you watch 'Simple made easy' by Rich Hickey - that was the definition of simple I was going with (as opposed to easy.)
>> Macros is just transformation over a data structure, albeit a data structure that is interpreted as code later on. It shouldn't add more complexity than other forms of data transformation.
Because they specifically inject before the eval section they _do_ add a lot of complexity. Writing complex macros is a lot of guesswork.
>> Neither do I, but I'm glad they exist. Core.async is built with macros, for example. They are part of what makes it possible to have core.async as a library rather than having to build it into the language.
I'm not sure what the benefit of this vs 'language features' is at this point.
Even if a macro is buggy, if the particular instances (i.e. macro calls) don't step on the bug, then we are okay. The expansion is done, and it is good.
Macros are deterministic and susceptible to regression testing with simple "X translates to Y" assertions.
We don't have to be overly concerned with the time and space performance of macros, either. The code in a macro expander can be structured for clarity and remain that way.
(Even in situations in which running Lisp apps are patched, the macro expansion doesn't have to be done in the application image. The translation unit can be compiled using a separate development image, and loaded as compiled files in the running app.)
If knowledge of how to use macros was better, I think some of the macro FUD would go away. If you're not using macros then you might as well not use a LISP. I'd agree though that using macros improperly leads to all kinds of problems.
Data structures in clojure are unimaginably better. In js you don't have anything like this. For example you can't tell how operations in js will perform since not even their complexities are documented.
Please elaborate about the better community. AFAIK js libraries have the half-life of months and you can't rely on them not being obsolete after you finish a project.
Macros are a tool which you don't have to use. Everything in the clojure world is optional. But when you need it you have something powerful. Try and emulate macros in js (like AOP in java) and you are in for a rude awakening.
...but really, it boils down to the fact that the people who were writing clojurescript in house wrote terrible spaghetti code that didn't work.
Without a tangible justification for re-writing (again) in clojurescript, the decision was made to rewrite it in es6 and throw all of the clojurescript away.
I think the lesson here is:
Having an excellent language (Clojure) can't save you from writing bad code.
For some reason writing clojurescript resulted in code that was a far lower quality than the clojure code from the same developers. /shrug
I can't explain why that is, but for us, it boiled down to: If you can't play nicely, you can't have nice toys.
Quality of the end product is more important than the tools used to build it.
Even hitting submit twice on an standard ajax powered form is likely to cause mild concurrency-related bugs on many popular websites.
Using Figwheel, this is just not true.
I do see ES6 making life hard for the compile to JS languages, though.
Not that JS doesn't have debugging pains either, but really the debugging story is the worst part of clojurescript.
Another thing to consider is how many of your bugs are because of an ill specified object, or because i held null instead of integer.
Also, I think the idea is to write specs for stuff that happens on the edges of the app, such as data received on the wire. If you have that covered, it probably would catch most problems you might encounter, such as receiving a null in a place where you expected a positive integer or such. Since it also destructures the data for you, specs for stuff received on the wire would save you the time you'd otherwise spend taking it apart manually, while simultaneously making sure it's not malformed.
Although I'm not that thoroughly read on spec, so I'm not sure I'm taking everything into consideration.