Worry About Data Structures

Many modern programming languages trace their lineage to either C or Lisp. C has spawned an entire ecosystem: Java, Go, C++, C#, and even Python and JavaScript have C-like syntaxes. On the other hand, Lisp gave rise to elegant and expressive dialects like Scheme, Common Lisp, and most notably today — Clojure.

A Lisp is fundamentally simple. It is built from just a few core building blocks. In fact, it doesn’t have a traditional syntax at all, at least not in the way C-derived languages do. When you write Lisp, you essentially skip the parsing step most compilers rely on, and instead write directly in the syntax tree — in the form of nested list literals. This is why Lisp code looks so alien: the parentheses aren’t misplaced — they’re literal structure.

Clojure and its derivatives enrich this core by using more expressive data structures. Instead of just lists, Clojure programs are composed with vectors, maps, and sets. That comes with a bit more syntactic variety — square brackets, curly braces, and the like — but the underlying idea remains: your code is your data.

Parsing a simple data structure, like JSON, is fundamentally easier than interpreting a complex language syntax like that of C#. And reading a Lisp is more like reading JSON than reading C#. You don’t need lex/yacc-style parser generators to interpret Lisp — you just need a reader. If XML and JSON are data, then Clojure code is data too.

This simplicity and flexibility is why those who fall for Lisp tend to fall hard. Since code is data, and data is easy to transform, code becomes easy to transform too. It’s common in Lisp to extend the language to suit the problem at hand. Domain-specific languages aren’t a gimmick — they’re a natural pattern. Inversely, describing program logic using plain data structures (that aren’t code at all) is also common. That’s what we call data-driven programming.

In Clojure, all data is immutable. When you want to change something, you create a new logical value — the old one remains unchanged. This also applies to general-purpose collections: lists, vectors, sets, and maps. They’re immutable and heterogeneous — elements of any type can coexist. That might sound unsettling to fans of static typing, but consider the tradeoff: In C-based languages, you might struggle to trust your data. It can be mutated unexpectedly, maybe by a colleague who doesn’t fully grasp your design. In contrast, immutable data is honest. You can reason about it. You can trust it.

“It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.”

In Clojure, we try to let our data structures guide functionality. This makes our code long-lived and easier to maintain. Linus Torvalds, legendary creator of Linux, famously said:

“Bad programmers worry about the code. Good programmers worry about data structures and their relationships.”

C, after all, is a good language with clear data structures: structs and arrays — abstractions just one level above machine code. It’s portable, yet close enough to the metal to make assembly-level performance understandable. But borrowing its syntax for higher-level languages like Java or C#? That’s… well, odd. Sure, it helped C++ programmers feel at home. But still.

“We were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp.”
— Guy Steele, co-author of the Java spec


All #art #clojure #csharp #data-structures #database #datomic #emacs #functional #haskell #history #immutability #java #jit #jmm #lambdas #lisp #pioneers #poetry #programming #programming-philosophy #randomness #rant #reducers #repl #smalltalk #sql #threads #women