Julia vs Clojure (or other languages [w/persistent data structures])

I hate to say it but Clojure seems like a better language for correctness, because everything is immutable (functional), while in Julia containers aren’t (by default). At least for concurrency, then it claims to be the best language (unlike Julia and Go, it eliminates race conditions, in an easier way than Rust), threading is hard in all languages and Clojure solved it with persistent data structures (PDS), However for parallelism things reverse and Julia is better.

Another reason to use Clojure is “spec”. The idea is that there will no longer ever be (API) breaking changes in libraries. An improvement on SemVer that Julia Pkg depends on, which seemed like a good idea at the time…

I hate the idea that there can’t be just one best language for everything, which is e.g. Rick Hickey’s view, maker of Clojure, and ClojureScipt which is a variant, or my understanding the exact same Lisp, it’s just that ClojureScript is made for the web/JavaScript ecosystem (rather than the JVM). It claims to be best language for web programming (frontend, compiles to JS, can use e.g. React).

Rick doesn’t claim Clojure is best for parallelism, and for it I believe Julia may already be the best language. Julia has a higher/est performance ceiling, since Julia doesn’t box (unless non-concrete types are used, i.e. non-optimized code), while Clojure always does boxing for all types/atoms. There are many similarities between the languages like both good for composition, and both have access to the compiler at runtime, which is a pro, or maybe a con, for compiled binary size… Julia has Lisp-like macros, and then I believe the same “power”, but the macros may feel more natural in Clojure?

I’m thinking of abandoning Julia for a while, to learn more about and immerse myself into Clojure, than I can possibly take ideas back to Julia. Clojure is good for “situated programs”, likely best for it, the type of programming most users are doing while Julia is better for linear algebra (or technical/scientific) if you really need the speed, not my main interest in programming. Neither language is mainstream, Julia likely ahead, the reason isn’t so much that I think it will help get a job (in Iceland) with Clojure, even using either language.

Clojure/Rick claimed to have the largest library system of all languages (at least at the time, from a very old 10-year-old? talk), since it’s based on the JVM, can reuse all Java/JVM libraries (and while not good for security, can also call C, and then other languages including Julia).

I would like to hear the perspective of people that have used both languages (the Julia ecosystem takes a lot from Clojure), know them well (and PDS), e.g. if any abandoned Clojure for some reason. There are older PDS-libraries in Julia (not optimized according to the docs), but also a brand new PDS library in Julia, recently announced here. But even with it, and it being fast (as in Clojure, are they fastest there? Rick aimed for within 2x for reading and 4x for writing such data-structures), that may not be good enough, because you want all data-structures you use to be PDS (for correctness). If Julia had them be default then you could opt out of them for speed (I’m not sure you can in Clojure, but likely you can with the typed Clojure option).

The main other pure functional/PDS language is likely Haskell (statically typed), it’s just harder to learn, and likely not worth it. Clojure is a dynamic language like Julia, and static typing is overrated (as a default)… Any other interesting pure-functional/PDS supporting languages? I had a bias against Lisp (non)syntax, Clojure is likely the best Lisp dialect, and the syntax actually claimed to be the heart of Clojure. I think Julia could in theory get all the best features of Clojure, expect for its syntax…

It doesn’t have to be either or, recently there was a library announced to call from Clojure to Julia (in-process, not sure that’s possible in the other direction, there is JavaCall.jl though, that should work to call Clojure since it has bidirectional interop with Java). There’s also LispSyntax.jl, if you really want the Clojure/Lisp syntax, but I’m more interested in the semantics, and it doesn’t support that.

One other thing, what are people’s subjective feeling about AI tools for Clojure (vs Julia)? ChatGPT didn’t work too well for Julia last time I checked, but it was updated to GPT-4 this week, so that could have changed the game for any minority language. It at least very much improved support for my native Icelandic. Before it could understand it pretty well, but writing it was very flawed, but now it’s almost perfect (according to objective stats it’s now better for it and many language than GPT-3.5 was for English). I don’t think it improved because of a larger fraction of Icelandic in training data. OpenAI is tight-lipped about all details of the training (unlike for earlier versions), but at least the training data ends in September 2021, so I read into that, that it may be the same data, just processed better (for longer).

I think you’re very deep in your research on the topic, and it’s not clear what response you want from the Julia community; most of your post seem to be about your understanding of various aspects of the two languages, some technical some philosophical, and finally, somehow chatGPT makes an appearance.

Trying to figure out what you want others to contribute (cuz I think you already have a lot of understanding of the topics):

I’m interested in what are the Ecosystem that takes a lot from Clojure, I only know GitHub - JuliaFolds/Transducers.jl: Efficient transducers for Julia, outside of deliberate meta-y / Lipsy things like (LispSyntax.jl) that by definition is Clojure related.

Sounds like you have reasons and decisions made. And sorry I don’t know what’s job market like in Iceland but maybe including remote work it’s not that bad for either language.

I do not think this is super important at this level of comparison. If “LLM generating mostly usable code” is very important, you should be looking at Python or C++ anyway, so I assume it’s not part of your workflow thus it doesn’t matter when you’re trying to pick between Julia / Clojure.


To quote Rick, Clojure code has fewer lines of code that other languages have files! He probably had (the verbose) Java in mind when he said that, I don’t recall the context. Julia is also excellent for concision (and composability). What I had in mind with AI tools is that is, this going to help or hurt them? Languages can be better or worse in isolation (for some task), before we had AI tools. But in the (far) future language might not matter as much, if AI writes all the code, and in the meantime, the AI tools could practically shift what are the best language to use (or learn).

When people write 80% of their code with AI tools (that was before GPT-4 update of ChatGPT), it seems relevant. And that was Andrej Karpathy, not some average guy, (former) Tesla’s director of artificial intelligence, top guy for the Autopilot, though unclear if it applied for him writing AI code (or other), maybe it/his (C++? Python?) code was already very verbose…

I worry that non-mainstream languages get left behind, but only in the short term. I’m not sure such fractions apply to Clojure (or Julia). I have a feeling, such best-case numbers are for/because of boilerplate code, and Clojure/Lisp has none.

The context window in GPT-4 has increased, up to 32K token if I recall. 1000 tokens are ca. equal to 750 words if I recall. That alone should help concise languages, but I’m also thinking could the code be too concise in the training data for AI tools to help (anyone know e.g. how well APL is handled?). Or the (non)syntax of Clojure/Lisp throwing off AI tools. I see for Icelandic, while ChatGPT is very good for it now, it seems to spell out words, i.e. rather slowly, a letter at a time, unlike for English. Could be because we have many compound-worlds like in German, unlike English (and/or because English is dominant in the training data). That letter-as-token(?) would likely be a good thing for Clojure. I was thinking parenthesis might throw it off, at least say if e.g. “))))))” would count as one token (likely never did), it would likely destroy understanding. You want each one to count as one token for sure.

Yes, I had transducers in mind, and also “FLoops: fold for humans™” which if I recall also Clojure-inspired, but both are under the same JuliaFolds umbrella, and more so maybe you counted as one thing. I admit I didn’t look much into these yet, and possibly they are just as good in Julia (or better?), though sometimes it makes sense to look at the original. At least when you’re learning (for me e.g. likely easier to learn practical things with PyTorch and/or TensorFlow than Flux/Julia ecosystem). I’m not sure there was more I had in mind, maybe just (rather trivial?) syntax-related stuff, that may or may not have had relation to Clojure.

reference? do they not read what the LLM spit out at all? what about large code base design conventions that can’t fit in LLM token limit? I mean by this logic company that uses Python can fire 80% of their programmers and just let PM talk to LLM :joy: we’re not there yet, when we get there, fine-tuning for large code base is same as fine-tuning it for Julia/Clojure so it not an issue.

idk man, tokenization is determined by your training data to maximize efficiency on common combinations of letters in your training set, I don’t think you want to extrapolate this far far into “saving token = better LLM = better for Clojure” like it doesn’t matter at all probably… if your language is niche it just uses more token

by itself it’s a pretty niche area in Julia, I’m sure it’s more niche than “Linear Algebra” which you said you didn’t care much.

Indeed, mutability is rarely needed, and high performance can be achieved in Julia with none or very few mutating operations. OTOH, mutable arrays are nice to have in those case when the easiest/fastest solution involves mutations.
Maybe static immutability guarantees are better sometimes, but still in Julia it’s very convenient to operate on immutable structures, including arrays.
If something is more convenient in Clojure in this regard, would be interesting to hear — speaking as someone who never wrote Clojure.

1 Like