This episode is for subscribers only. Sign Up or Log in to watch it.

23. deftype and definterface

Published 19 January 17

Clojure is built on a well thought out set of abstractions. To implement these, it makes use of the ability to define abstractions in the host language, namely Java interfaces, and the high-performance polymorphism that they provides.

As a Clojure programmer you don’t have to resort to Java to achieve the same thing. All the facilities are there to create interfaces, and to create types that implement interfaces, getting you as close to the JVM as you need to be.

Show notes

If you came from an object oriented or statically typed programming language before coming to Clojure, you might have been disoriented at first. Where are the classes? Where are the types?

Clojure deliberately stepped away from the “kingdom of nouns” found in other languages. Instead of having many different types, each with their own custom interface, Clojure code tends to use a small number of general purpose data structures. This way the focus shifts from how the program is structured, to what the program does.

This works well because Clojure’s data types are built on a small number of abstractions, like Seqable, Associative, or Indexed.

 listlazy-seqmapsetvector
seq?truetruefalsefalsefalse
seqable?truetruetruetruetrue
associative?falsefalsetruefalsetrue
counted?truefalsetruetruetrue
indexed?falsefalsefalsefalsetrue
ifn?falsefalsetruetruetrue

“Abstraction” in this case refers to having shared functions that work across a number of concrete types. Take for example an equality check. Comparing two vectors is very different from comparing two numbers, you would need a separate implementation for each. And yet we have a single function that does both. The equality check automatically adjusts itself to its inputs. This is called “polymorphism”, from the Greek for “many shapes”. You can also say that it “dispatches” to the right implementation based on the type of its arguments.

(= [1 2 3] [1 2 3])
(= 5 7)