deftype vs defrecord
From OO to Clojure Workshop!
Watch my free workshop to help you learn Clojure faster and shift your paradigm to functional.
Summary: There are two commonly used ways to create new data types in
defrecord. They are similar but are intended to
be used in two distinct use cases.
deftype is for programming
defrecord is for domain constructs.
In a recent lesson in PurelyFunctional.tv Online
Mentoring, I briefly
deftype, then quickly moved on. I
think it's worth exploring what they're used for and what their
To explain what the difference is, let's look at the field of accounting. Accounting is everywhere. Businesses of all types have accountants. An accountant at a hardware store definitely has to know accounting and also know a bit about hardware, which is the business domain. An accountant at an ice cream shop will probably learn about making and selling ice cream. But there is still a very clear division between accounting and the business domain. There are accounting terms and concepts that are clearly generic accounting terms. And then there are some ice cream-related terms that the accountant will use in the accounting. It's accounting about ice cream.
Clojure tries to help the programmer with the same conceptual division. When we're programming about ice cream, we're going to use a lot of computer/programming terms ("vector", "function", "string", etc.). But there will also be some new terms in our language that are representations of the domain, like "flavor", "recipe", "price", etc. Everything is divided into programming constructs and domain constructs.
If you're making a new programming construct, like a new data
structure, you want to make a new class but retain low level
control. You want to define the fields, say what protocols it
implements, and how equality is defined. That's what
deftype defines a new type with specified fields (you can even make
them mutable) and one constructor and nothing else. Very barebones. Of
course you can implement protocols right inside the
deftype to define
If you're making a new domain construct, you don't want low level.
That was a mistake Java made, forcing programmers to write tons of
domain classes and deck them out with getters. Each class was a new
thing, incompatible with any existing tools. In Clojure, you use
defrecord if you want to create a domain type. You can think of
records like hashmaps but with their own class.
they have equality and hash
defined for you, as you would expect. And they can store arbitrary data
using the same access
as hashmaps. You can
count, etc, on any record.
Records will have their own class and can implement protocols and
interfaces. So you get the best of using reusable data structures and
type-based polymorphism. If you don't need the polymorphism, you
should probably just use a hashmap.
This division between programming constructs and domain constructs is so helpful. It's an example of one beautiful thing about Clojure: it's a language helping you write software in a better way. You have different needs when you're making domain values and Clojure provides for those needs.
So, to wrap up,
deftype is for programming constructs and
defrecord is for domain constructs that need a custom type. When
you're engineering your software, it's useful to ask if you're
building a programming construct or a domain construct and choose the
right tool for that job.
If you're interested in learning about how to use
defrecord, I have several examples in the PurelyFunctional.tv Online
Mentoring program. It's a
step-by-step program taking you from dabbler to Clojure professional. I
release new lessons all the time, in video form. You can get access by
signing up here.