Which piece of code do you think makes ClojureScript significant?

Your arguments are wise but i really dont think anyone can sell it, saying hey you should learn clojure and if anything is not supported just look at the Java Docs and you can reuse everything else from there.

Whats wrong with Java Docs? It might not look fancy but once you figure out how its structured it is pretty good. I haven’t convincingly better API docs anywhere yet. They more or less look alike everywhere.

Seriously though … don’t tell anyone that you might need to use Java/JS sometimes. If anyone ever gets to this point they will probably have written enough code to be hooked. Figuring out how to do interop is just a natural step in the learning process. Having this option at all is very powerful and many languages fall apart at this point.

1 Like

It’s a lisp carefully designed from first principles around immutable data structures with a practical approach to functional programming. These are not features in the sense of a particular morsel of syntax sugar, as @thheller’s comment “it wasn’t a single piece of code that attracted me” exemplifies. It’s an entire programming style where each element has benefits that comes together as more than the sum of its parts. For instance, “as a dialect of Lisp, [clojurescript] has a code-as-data philosophy and a powerful macro system”, each of which sounds merely okay until you see firsthand all the implications that has across architecture and workflow.

I think that’s the pitch. This may not convince folks who want to avoid a big bite of “new way of doing things” but it is what it is.

(One aspect of ClojureScript that actually is a feature, and which we may sometimes not speak enough about, is Google Closure, both as a powerful library and as a path to the sorcery of dead code elimination.)

clojure needs a good standard library that is compatible across hosts

Doesn’t most of Clojure core already work the same in both ClojureJVM or ClojureScript? To the extent that it doesn’t, it largely shouldn’t. Regardless, Clojure is designed to be a hosted language, it’s fundamental to what Clojure is and to Clojure’s value proposition as a lisp with elegant interop, and I do not expect that to change. For the same reasons @thheller stated upthread I think such a change would be unwise.

Finally, I’d like to address this:

My best guess is that for a lot of people in the ruby community, ruby is their first language and much of the Java hatred is propagated by the author of Rails, DHH. And most first timers are susceptible to religious ideas, it is only after a few yrs of development you see a clear picture and look beyond your current first love. You see the first love is always too infectious and languages are no different. Infact my own ideas about Java were reinforced in the ruby community before i realized that Java is bad but JVM is industrial strength VM second to none.

This kind of infatuation with programming languages that you describe is a real thing. But the conclusion we should reach from it is that we should do outreach that focuses on explaining and teaching a better way, not that we should lie to them by saying that they will be productive in Clojure/ClojureScript without needing to challenge their own immature view of programming.

3 Likes

I am not really bashing Java Docs, my limited point was if anyone who doesn’t know Java, would have a hard-time understanding it. And if you are trying to learn clojure, but parallely trying to learn Java aswell as a courtesy of clojure may not be such a welcome thing for many.

1 Like

It isnt consistent, for instance something as basic as edn serialisation and deserialisation in clojure vs clojurescript.

In Clojure

(defrecord Human [name age sex])
(def new-person (->Human "pankaj" 33 :M))
(read-string (prn-str new-person))

In Clojurescript

(defrecord Human [name age sex])
(def new-person (->Human "pankaj" 33 :M))
(cljs.reader/read-string (prn-str new-person)) ;; This would fail

Why does the reader in cljs fail? Why dont they just work the same?

This is unfortunate yes but the technical reason for this is that ClojureScript cannot lookup classes dynamically at runtime. Therefore it cannot map the your.ns.Human symbol to the class. But in general records are not part of actual EDN so in a sense CLJS is correct.

Clojure 1.9.0
=> (require '[clojure.edn :as edn])
nil
user=> (edn/read-string "#cljs.user.Human{:name \"pankaj\", :age 33, :sex :M}\n")
RuntimeException No reader function for tag cljs.user.Human  clojure.lang.EdnReader$TaggedReader.readTagged (EdnReader.java:801)
;; which matches the CLJS error
Error: No reader function for tag cljs.user.Human.

clojure.core/read-string should not be used for reading EDN data since it is unsafe and can be used to eval things and other dangerous stuff.

1 Like

Try something as simple as a serialized edn string with record namespace :

(cljs.reader/read-string "{:name \"Pankaj\"}\n")

The above would work on lumo and planck but not if you bring a cljs repl using clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.9.946"}}}' -J--add-modules -Jjava.xml.bind -m cljs.repl.node

This is getting way too off-topic. It works just fine in my node repl? Did you maybe miss a (require 'cljs.reader) first? Feel free to send me a direct message to help you troubleshoot this. Or open another thread, we should not hijack this one.

2 Likes

In fact, a patch worth considering would be to alias clojure.edn to cljs.reader to ameliorate this confusion.

2 Likes

I am one of those javascript guys who happens to hate Java. My first approach to programming was through video game programming on a language that mixed C and pascal. After that I have programmed in C, C++, php, python, javascript, bash, ClojureScript, Haskell and of course Java, and it happens that there is no language that I hate most than Java . My problem is not with the JVM at all, and I don’t think any smart person has anything against it neither, it’s an impressive piece of machinery. The problem (and makes sense, of course) is that everything related to the JVM involves in some way or another Java, which is the bad part: unless you are an end-user you will have to write or read some Java. I was first attracted to Clojure by the idea of writing code for the two mainstream virtual machines of nowadays, but after developing some toy projects with it I came to the conclusion that you need to know the host language very well to be able to use it. This is true for me in the case of javascript, but it will never be for Java. In fact being able of writing stuff that will run on the JVM without writing any Java was one of the main selling points, but seems to be impossible. That leaves me with ClojureScript alone, so I think that finding motivation to stick with Clojure even if your are not going to target te JVM is important for many people.
I have to admit that the weird syntax was also attractive to me, but I don’t think we can shell this to many people :smile:

2 Likes

I think it’s important to be able to read the host language and be familiar with its idioms, and of course the ease of doing that scales up with ones reading proficiency in the host language.

I think the most Java I’ve written in a Clojure context was some throwaway code demonstrating a minimal example of a bug in a Java package over which I maintain a Clojure wrapper. The Java was only necessary because I wanted to literally “speak their language” when reporting the bug.

I think it’s quite rare for Clojurists to write any Java for their Clojure projects. Have you found it necessary?

Sorry if I gave the impression that I wrote anything apart from configurations in Clojure. I only tried ClojureScript under nodejs. I didn’t need to write javascript code, but I had to write some code that was just javascript with a different syntax. Based on that experience I extrapolated that to Clojure. Maybe my judgment was not fair knowing that ClojureScript on node was not the primary target of the community and that may be the reason why I had to write so many interop by hand.
Maybe I am mistaken and it is different for Clojure, which is the original language and server side java is the main target

To answer the original question, for me, the killer feature of ClojureScript is the way atoms are built into the language and enable an observer pattern that works flawlessly and with the full complement of the built in language features.

This feature does what redux + immutable.js, mobx, and similar libraries try to do in JS. But these libraries all require you either to conform to a subset of the language (e.g., in mobx you have to manipulate arrays carefully) or require a giant amount of boilerplate and careful coding conventions (redux).

In cljs, you can just manipulate the state and everything else happens automatically. It seems to me that it is just not that easy to replicate this feature in javascript in a natural way.

4 Likes

In cljs, you can just manipulate the state and everything else happens automatically. It seems to me that it is just not that easy to replicate this feature in javascript in a natural way.

I would second this, especially with re-frame with its defined one-way dataflow everything is so much more understandable and easier to follow.

1 Like

I guess I’m starting to realize, maybe most of the ClojureScript trade-offs were due to its compiler being Clojure only. The special handling of macros, the fact very little is reifiable, the lack of eval, the more complicated repl setup, etc.

Now that self-hosted ClojureScript is real, do you think we could see some of those trade-offs be revisited? Maybe once the JavaScript Google Closure variant is out of alpha? Like reintroducing reified vars and namespaces, adding eval back, letting macros live in cljs namespaces, etc.?

Let’s not conflate quirks with explicit design choices. Self-hosted ClojureScript is impractical for most web applications due the order of magnitude increase in the base payload. Making self-hosted ClojureScript act differently is a portability liability.

Suffice to say the semantics of ClojureScript haven’t changed in many years and they aren’t going to.

1 Like

Fair enough, I edited my post.

I’ll work to educate better, and most of these are honestly small, you just have to know about it and how to do it the ClojureScript way instead.

I think this two tweets are very good ways of being positive about clojurescript:


And the best part is that they from the official guide!

2 Likes

I get where you’re coming from (switched to cljs 2-3 years ago from react+webpack). It’s not “just” hot reloading though, with figwheel you get a REPL into the app running in the browser. That just comes with the figwheel setup, and it integrates very well with Cursive in IntelliJ (switches the REPL to cljs mode) and Emacs, I imagine, for those with enough grit :wink:

This means that I can evaluate stuff in my REPL that directly uses re-frame’s “live” db atom, and events, subscriptions as well. I can trigger DOM events, or query the DOM, play around with my own namespaces and functions, mess around with Google’s Closure library, and so on. All the benefits of the REPL-workflow combined with hotreloading … unmatched, so far. Don’t forget that you’re getting all the other benefits from using Clojure in the first place, for which you’d need strong conventions, libraries and/or tooling set up (Immutable.js and friends) in webpackland.

3 Likes

I get the sense that many Javascript refugees just use hot-loading, which is familiar from their previous ecosystem, without ever realizing the tremendous advantages of also having an editor-connected REPL. :man_shrugging:t2:

2 Likes