Diving into Clojure with JS Experience: Depths, Treasures, and Wonders
January 17, 2025
October 22, 2024
Freshcode
Hi, my name is Pasha (Pavel, Pablo, Paul) and, to be honest, there is nothing extraordinary in my prequel to Clojure Trek.
I'm a JavaScript developer with 2+ years of experience. Six months ago I first met Clojure, and it hooked me. And so the story began!
I have been learning Clojure in my free time for the past six months, and today I want to share my impressions with you.
About me
Syntax
Sure, the first thing that caught my eye was unusual syntax.
I was already superficially familiar with Assembler, C#, C++, Pascal, Visual Basic, Python, Java, and JavaScript, but Clojure was something I'd never encountered before. Unless I saw something similar during my history of programming languages lessons at university. But honestly, I didn't expect anyone to use such things today!
The first strong impression was… )))))))))))))). What cheerful people are these functional programmers... My brain was looking for function names but couldn't find them. Later, I discovered that the first argument enclosed in parentheses is a function name (set-mood :surprised).
It took a while to adapt to the new Clojure world (at that time, I was still actively working on a JS-based project). I thought I'd never have to do something like:
- (a + b) ; clojure
- [a b c] // js (where are the commas...)
- foo() ; clojure
- if … // js
Over time, this became less, but sometimes, my hands failed me.
Sure, the most helpful thing was practice. Especially challenging tasks that require deep consideration of code logic. Thoughts about syntax faded into the background...
After studying some basics of Clojure, I started writing a program rendering the Mandelbrot set in HTML5 canvas. Not perfect, not at all idiomatically. But it helped me dive deeper into language and get used to it.
Data types
Clojure data types that stand out as the most interesting and curious for me:
- :keywords
- symbols ;I didn't immediately understand how to use them, but it became clear later
- 1/2 ; it's unusual to see rational fractions, but I thought that it would be helpful for calculations without loss of precision
Clojure collections and code-as-data
First, I wanted to learn how to create and modify datasets.
I truly enjoyed the vast number of functions available for working with collections in the standard Clojure library <medium>clojure.core<medium>. Clojure collections offer an interesting juxtaposition, they can also act as functions.({:interesting "to use a map as function"} :interesting)
The experience of using the clojure.core functions <medium>reminded me of Lodash, a JS library<medium>. For example,
{{blognn7-2="/custom-block-to-blog/three-page"}}
_(_.range(10)) //js + lodash
.map(x => x + 1)
.map(x => console.log(x) || x)
.map(x => x * x)
.filter(x => x % 2 === 0)
.take(3)
.value()
(->> (range) ;clojure
(map inc)
(map (some-fn println identity))
(map #(* % %))
(filter even?)
(take 3))
Both variants involve the logic of lazy collections implementation. Therefore, the calculations include values from 1 to 6 only, and there is no point in going any further because the answer (4 16 36) has already been completed.
Some things in working with collections were quite puzzling. For example, I was constantly confused with lists and vectors.
Code-as-Data is a concept implemented in Clojure, and I'd been searching for it for a long time. I've always been interested in creating my own data constructs, my own DSP because I thought it might be handy in describing program logic.
Clojure allows you to do something similar using macros:
(defmacro say [& code]
(let [words (map str code)
message (if (= (first words) "that")
(next words)
words)]
`(clojure.string/join " " '~message)))
(say that i am very happy) ;”i am very happy”
(say macroses are cool) ;”macroses are cool”
In truth, this concept is challenging to assimilate. Understanding how it works and what happens at runtime and compile time takes time and practice.
But 'Code-as-data' is precisely one of the reasons why I fell in love with Clojure and why I have no more questions and no complaints about syntax and the parens forest.))))
Clojurescript
JS features and the elegance of Clojure is a perfect combo.
I've developed quite a lot in React. When I discovered ClojureScript I tried Reagent. There is no dissonance; hiccup-syntax is very convenient, and most key React features are usable from Reagent.
Other
I thought that lack of variables would be a big problem, but as it turned out, that wasn't the case at all.
After analyzing my JavaScript code, I discovered that, in fact, we didn't use mutable operations so often. Instead, we saved intermediate results in const variables and used them in other functions. In some cases, we used let variables in JS, but they also can be replaced by reduction or recursion.
Speaking of the frontend, data persistence requires using state management tools quite similar to Clojure's Atoms or Re-frame events.
Finally, asynchrony. When I first read about concepts such as asynchrony, сoncurrency, and parallelism in Clojure, it seemed to be very difficult. However, with a deeper understanding, everything fell into place.
El epilogo
Clojure is really beautiful. With it, it's possible to write some things much more concisely and readably compared to other programming languages.
Every time I encountered something unusual, I tried to find some analogy or similarity in other languages and analyze it in such a way.
P. S.: I don't think I am experienced enough to offer advice, but anyway, here, you can check some sources I used when I was starting with Clojure:
- clojuredocs
- clojurians-log.clojureverse.org (here I found answers to some tormenting questions)
- clojurescriptmadeeasy.com (I enjoyed articles and how-tos about cljs)
- "ClojureScript: Up and Running" by Stuart Sierra, Luke VanderHart
with Freshcode