This is just fantastic! As David himself mentions - this might not be extremely pragmatic but it sure as hell as cool. For me it means that I can get back to writing my web-based Clojure book without being dependent on Himera[0], which although great, is really hard to work with.
Awesome work by @swannodette and team!
It horrifies me that anyone would have been dependent on Himera to do real work. While I'm proud that it filled a gap for a few years and consider it a successful experiment, I'm happy to know that it's effectively unnecessary now.
Haha! Well, it was not real work - just a fun experiment[0]. Thanks for Himera, though. It was great while it lasted :)
[0] - https://github.com/prakhar1989/gitbook-plugin-clojurescript
EDIT: How do you debug your work? What traces do you get back? Can you still do REPL (like Emacs/Slime) this way?
ClojureScript is now self-hosting, which means that you can eval any valid ClojureScript, so yes, eval in ClojureScript is now equivalent to the eval in languages like Clojure, Racket or any other Lisp.
Usually when a language is bootstrapped, that becomes the new norm. For instance, Go was originally mostly written in C, but since 1.5 Go has been written in Go. However, the Java version of the ClojureScript compiler can leverage Google's Closure Tools, which include a rather useful Javascript optimizer. This means that we'll still want to use the Java version of ClojureScript in most cases.
The best way to think about this development is that it is a client-side compiler for ClojureScript. In client-side development, you are constrained by the limitation that all code must be in JavaScript to be executed by the Web browser, which is why this compiler "compiles to" JavaScript instead of machine code. JavaScript is the assembly of the Web, right now (until things like WebAssembly get more useful and popular). Once the ClojureScript is compiled to JavaScript, the JS can be executed by the browser (which of course involves an additional JIT compilation step). This might sound "dirty" if you are used to thinking about non-Javascript development, because it involves two separate compilation steps, but it is unavoidable, once again until something like WebAssembly becomes popular.
So, this is a client-side compiler for ClojureScript. A server-side compiler already exists, which is what you would use if you wanted Emacs/Slime support, or if you were developing a "real" Web application for deployment, because in that case you would want to pre-compile to JavaScript on the server, and distribute the compiled JS to the client.
It doesn't really make sense to talk about Emacs/Slime running on the client, until someone makes Web app for it. You could use a socket-based REPL to communicate from the client to the server but I don't really see the benefit, when you could just use the server-side compilation model and avoid the network overhead.
Thank you so much.
...and eat and sleep, of course.
The one area I have not been happy with is clojure's startup times so hopefully this fixes that going forward.
Edit: this new development (CLJS compiled with CLJS) is remarkable because previously, compiling CLJS required a running JVM. One could still compile automation scripts and run those, but that wouldn't really be true to the "scripting" style anymore.
-- Rich Hickey
(or so I've heard)
Not that 300K should be considered a huge amount by today's standards anyway.
How does clojurescript compare to elm/purescript ?
Then I ask if they've seen Python before, to which most say 'yes', and I say, 'there you go, it's Python now'. And I can immediately see the look of surprise when they see that _similarity_, because the similarity is then hard to unsee!
I recommend that trick to any others trying to open minds and challenge preconceived notions in their surroundings. :-)
Side note: I've made the point that nested SQL expressions have many nested parens, too, which we've all done. And that the sum of parens+brackets+braces is similar to other languages, just the distribution is different. Neither of those 2 arguments work as well -- I guess because it's not visual and striking?
This approach reminds me of when people say, hey JS has classes and constructors just like Java does! And then proceed to write Java in JS.
So basically I'd do any serious development with Clojurescript. Elm is a really cool thing with a small community that's fun to mess around with.
Not only that but having a single source of truth for your app's state, using only pure functions and non-stateful components to render your view allows you to do things like:
- build a time traveling debugger
- serialize your app's state and store it in your session so that users see exactly the same view when they log back in
- trivially do server side rendering
I have yet to be convinced that stateful react/virtual-dom components and/or GraphQL add any tangible benefits in the majority of cases.Clojurescript is a Lisp with dynamic typing, Elm/Purescript are ML dialects where (static) typing is much more important, in Purescript more so than Elm.
I think Elm is interesting because it takes a rather uncompromising FRP approach to web development. Clojurescript does not strive for the same degree of functional fundamentalism.
Additionally, I find that algebraic data types are by far the most natural and complete way to model your data and pattern matching is a powerful way to write succinct and readable code that manipulates that data. The fact that Lisps don't normally come with ADTs (incl. clojure) is a real shame.
PureScript got its own Hoogle [2] recently. It lets you search for functions by stating their argument and result types. This has worked far better for me than any IntelliSense, and its miles ahead compared to rummaging through the docs of a dynamic language hoping to hit a jackpot.
Although the community is small, the speed at which the language and its libraries are moving is quite amazing. For the cases where a package doesn't yet exist, its very easy to write FFI bindings to an existing JS library
On the minus side, there is no "template purescript" yet, and generic deriving is WIP, so some things (like JSON serialization) are still a bit more tedious than absolutely necessary.
The efficiency of the generated code may also be a concern. For example, currying is implemented in such a way that a function call with 3 arguments always generates both the result and 2 temporary JS closures. This can be very costly in certain situations. I find that library documentation is also sometimes lacking, however types and typeclasses do help with that somewhat (the latter only once you learn what each typeclass means).
Finally, something to keep in mind if coming from JavaScript: unless you know Haskell the learning curve for PureScript is far steeper than ClojureScript. Its about as steep as Haskell's. There is a great book available to help with that [3], and almost all of the the knowledge gained there will easily transfer to Haskell. Since PureScript compiles to readable JS, looking at the compiled code made it much easier for me to understand the mechanics of certain features (Eff <-> thunks in particular was quite a revelation) which in turn helped me understand those features
I haven't used ClojureScript much, but it does seem to have more mature, battle-tested persistent data structures (vs purescript-maps) and UI library (om vs purescript-halogen, although halogen seems very promising). There is also a type system (core.typed) which while not as principled as PureScript's, its still amazingly expressive - and since its gradual, you can start fully dynamic and then add types whenever you feel like doing that to parts of the codebase.
[1]: https://www.reddit.com/r/haskell/comments/3e10ea/til_instant... - last paragraph also applies to PureScript
Was going to say Shen does, but then again I only see pattern matching. Anyway, you might want to check it out:
I do agree purescript is awesome though :)
Check out David's other blog posts, ClojureScript synonyms[1], and http://clojurescriptmadeeasy.com.
One thing that's simpler in ClojureScript is that it only has one type of shared mutable reference, the Atom. Atoms are uncoordinated and synchronous. But Clojure has more types, with different behaviour characteristics. So in a way ClojureScript is simpler and could be the introduction.
In terms of learning, it's probably easier to learn Clojure at the very beginning.
It's simpler to get repl working and get a project building with Clojure right now. Not much simpler, but simpler. And at the very beginning, when the toolchain is magic to you, that matters.
As early as you like you can switch to Clojurescript, learn the handful of small differences and go from there.
download, run, and you have a clojurescript repl ready to go on osx at least.
So, I see no problem with learning either. Especially when you first jump in you are concerned more with the language "proper".
But, the opposite is in flight: ClojureScript now has support for depending on libraries that are packaged using the CommonJS system.
http://www.matthewstump.com/misc/2012/06/04/writing-nodejs-m...
Should be really very easy to do, you only need to study what cljs compiler emits and the docs for Google Closure Compiler JS libs.
Also looking forward to seeing some code examples of Demand-Driven Architecture[0]. Does anyone know of any edifying clojure code examples?
[0] http://www.infoq.com/presentations/domain-driven-architectur...
Keep up the good work. Clojure & ClojureScript are awesome.
Here's an example of a repository that I've repurposed to compile both Clojure + Clojurescript.
I think this opens huge computer science educational opportunities. Imagine a LOGO DSL inside your browser. With all the power of cljs. I am very excited!
Are there any plans to use mostly the same backend for Clojure and Clojurescript? It seems that since the languages are almost the same, it's only the code generation part that would be different?
There are no plans for the same backend AFAIK.
It was a fun project, and I learned a lot, but I ended up reimplementing the whole thing in Clojure+Java because performance and DB access was so much better in this use case. Having only a single event thread kills Node relative to the top JVM servers.
The short of it is that a load function is passed to `cljs/compile-str`, which provides the mapping. In this case, it doesn't bother to do any mapping because it knows that it is loading `bar.core`. However, `bar-url` could instead be in a map from the namespace to the URL. Surprisingly simple, actually!
1. https://github.com/swannodette/swannodette.github.com/blob/m... 2. http://swannodette.github.io/assets/cljs/bar/core.cljs
If those functions need to call into other ClojureScript namespaces that you've already compiled into your code then the analysis cache would need to be populated so that eval can operate properly.
For reference, here is cljs.js/eval: https://github.com/clojure/clojurescript/blob/v1.7/src/main/...