Coming To Clojure from JavaScript

Published: 2020-08-11

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 the let 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.


About me

I write about life as well as my mistakes and successes as I learn to build a business. I'm building a self-funded startup (Pairwise).


PrevAll Posts

Thoughts? Let's chat on Twitter or via Email :)