In Clojure, if you want a basic OOP behavior without killing yourself to fully implement Java classes and interfaces in Clojure, the preferred technique is to use records. Sometimes implementing protocols in records suits your needs, mostly due to speed of code execution. However, if you want polymorphism with your records, then multimethods are where it’s at.
Admittedly, multimethods are very flexible, so the technique I’ll show you is one of many techniques you could use. The basic pattern I use for inheritance with records, is to use the
derive command with keywords that are kept as a value in the record. For example,
(defrecord food [
(defn construct-food [name color yummy]
(->food ::food name color yummy))
(derive ::fruit ::food)
(defrecord fruit [
(defn construct-fruit [name color yummy needs-peeling]
(->fruit ::fruit name color yummy needs-peeling))
type is used to track
isa relationships of
derive is used to set
::food as the parent of
::fruit . Notice the use of custom constructors to set default values for
type in the records.
Continue reading “Clojure Record Heirarchy”
Want some Object Oriented Programming in Clojure? Here’s a quick example.
Let’s create a dog object.
"Just a protocol"
(barking [this] "bark")
(hungry [this] "hangry")
(defrecord Dog [breed ^Integer age color]
(barking [this] (str "barking my breed ... " (:breed this)))
(hungry [this] (str "I'm so hungry I could age one whole year to ... " (str (inc (:age this)))))
(sleeping [this] (str "Really tired, and it has nothing to do with my fur color that is " (:color this)))
Now let’s use the dog object.
[temp2020toss.dogo :refer :all])
(:import (temp2020toss.dogo Dog)))
"I don't do a whole lot ... yet."
(println "Hello, World!")
(let [my-dog (Dog. "chow" 8 "green")]
(println "-->" (:breed my-dog))
(println "-->" (barking my-dog))))
See, OOP in Clojure is fairly simple. This sample uses protocols with records, but you can add polymorphism with just a little extra work. For polymorphism, use records and multimethods.
I absolutely love the user razvan’s Clojure
defrecord example over at stackoverflow, so I copied it here. I know I’ll never find it again if I don’t. Look at the original over on stackoverflow at this link.
Here’s the example …
Clojure defrecord example:
;;define Address record
(defrecord Address [city state])
;;define Person record
(defrecord Person [firstname lastname ^Address address])
;;buid the constructor
(defn make-person ([fname lname city state]
(->Person fname lname (->Address city state))))
;;create a person
(def person1 (make-person "John" "Doe" "LA" "CA"))
(:city (:address person1))
If you’re looking for more information on combining protocols with records in Clojure, then Matthew Boston has the blog for you!