status
published
dsq_thread_id
Clojure and JavaScript have a surprising amount in common. I've been pleasantly surprised that a lot of what I know already coming from the JS world applies in Clojure too.
Functional Programming
JS is a very flexible language in that it does not enforce any particular ideology. In particular it gives you both classes and first-class functions, which means out of the box you can write your programs in an extremely object-oriented way or an extremely functional way.
I was never indoctrinated into the Cult of OOP so naturally I've tended to write most of my code in a functional style. For example, in JS:
// First I need to define a few things that are included
// in Clojure but not in JS
// comp is short for "compose". It combines functions
// from right to left
const comp = (...fns) =>
fns.reduce((f, g) => (...args) => f(g(..args)));
// str converts its args to strings and joins them
const str = (...args) =>
args.map(String).join("");
// inc, short for "increment", will increment an integer
const inc = (x) =>
x + 1;
// Now combine some functions to make a new one. Note
// that the functions will be composed starting at the
// bottom. So the multiplication comes first.
const func = compose(
str,
inc,
x => x * 100);
func(1); // => "101"
In Clojure:
; This code may appear much more concise than the
; JS code, but that's largely because clojure includes
; the functions we need out of the box
(def func (comp
str
inc
#(* % 100)))
(func 1) ; => "101"
So similar!
If you're not used to functional program this may all look like gibberish, however, coming from a background of using functional programming in JS clojure feels oddly familiar.
Destructuring and "rest" parameters
In JS and in Clojure we can extract values from collections in a structural way. I imagine that this syntax is foreign to anyone coming from a language that doesn't have it, but if you're familiar with it then you'll be quick to start using it in Clojure too.
JS:
const arr = [1, 2, 3, 4, 5];
const [a, b, ...remaining] = arr;
console.log(a, b, remaining); // => 1 2 [3, 4, 5]
Clojure:
(def arr [1 2 3 4 5])
(let [[a b & remaining] arr]
(println a b remaining)) ; => 1 2 (3 4 5)
There are of course some differences here, but the two parts to focus on are:
[a, b, ...remaining] = arr
[a b & remaining] arr
See the similarity? To make it ever more explicit we can use commas (
,
) in the Clojure example: [a, b, & remaining] arr
. Commas are considered whitespace in Clojure.The key differences to notice are:
- The use of
...
in javascript vs&
in clojure.
- JS uses the
=
symbol for assignment, whereas thelet
construct in clojure simply uses a space.
Immutable Data (What?!)
This one is a bit subjective since JS does NOT force you to use immutable data, however it is possible and is even necessary in certain architectures. Namely, lots of front-end programming over the past years has made use of immutable data.
If you're worked with React and especially if you're worked with Redux then you've used immutable data before, even if it's taken the form of manually returning new objects or arrays.
Example:
const incCountState = (state) => ({
count: state.count + 1,
...state
});
In this example we manually create a new object using the spread operator on state, thus our new state is a different object from the old state which has not mutated.
Example 2, for anyone who's ever used Immutable.js:
// Here we assume state is an Immutable.Map
const incCountState = (state) => state.set("count", state.get("count") + 1);
As the name implies, Immutable.js is very similar to Clojure's data structures. It does not allow you to mutate anything except very explicitly.