This article is part of a series describing a port of the samples from Practical Common Lisp (PCL) to Clojure. You will probably want to read the intro first.
This article covers Chapter 17, Object Reorientation: Classes.
Common Lisp defines classed with defclass
. In Clojure, I can define structs with defstruct
:
The bank-account
struct has two basis keys: customer-name
and balance
. I can specify values for these keys, in the order they were declared, using struct
:
With struct
, all the basis keys are optional:
If you prefer named parameters, you can use struct-map
instead of struct
:
Very important: structs are still maps. I can specify additional keys that are not part of the basis:
The examples below assume an example-account
:
Pedants call get
to access a structure value:
But that' way too much effort. Structures are functions of their keys:
If the struct keys are symbols, I can go the other way. Symbols are functions of structs:
Other than symbols, what else can be a structure key? Ah, sweet immutability. Since Clojure data structures are immutable, any of them can function as keys.
I can use assoc
and dissoc
to get a new map with a key added or removed:
But I can't dissoc
from example-account
because you can never remove a basis key:
Since structs are also maps, default values are easy: just merge
them. The example below doesn't even use a struct. (Often duck typing is good enough.)
If I want to validate fields, I can just write a validation function. Here is a validation that simply requires non-false values:
Of course, if I wanted to create tons of different structs with similar validations, I could build some helpers. Macros + metadata would be one way to go.
Clojure's structs fill some of the same roles as Common Lisp's classes. The exmaples above show how to create and access structs, and how to add default values and validation.
That said, Clojure's structs are not classes. They do not offer inheritance, polymorphism, etc. In Clojure, those kinds of jobs are handled by the incredibly flexible defmulti
(see the previous article for details, especially the references at the end).