Methods in Clojure
Clojure supports functions defined on record types, which are similar to methods on structs in other languages.
(ns methods-example
(:require [clojure.string :as str]))
(defrecord Rectangle [width height])
;; This area function takes a Rectangle as its first argument
(defn area [^Rectangle r]
(* (:width r) (:height r)))
;; Here's another function that operates on a Rectangle
(defn perim [^Rectangle r]
(+ (* 2 (:width r)) (* 2 (:height r))))
(defn -main []
(let [r (->Rectangle 10 5)]
;; Here we call the two functions defined for our record
(println "area: " (area r))
(println "perim:" (perim r))
;; In Clojure, we don't need to worry about pointers vs values
;; All data structures are immutable by default
(println "area: " (area r))
(println "perim:" (perim r))))
;; Run the main function
(-main)
To run this program, save it as methods_example.clj
and use the Clojure command-line tool:
$ clj methods_example.clj
area: 50
perim: 30
area: 50
perim: 30
In this Clojure example, we define a Rectangle
record type using defrecord
. Instead of methods, we define functions that take the record as their first argument. This is a common pattern in Clojure and other functional programming languages.
The area
and perim
functions are defined outside the record, but they operate on Rectangle
instances. This is similar to how methods work in other languages, but with a more explicit passing of the record as an argument.
In the -main
function, we create a Rectangle
instance and call our functions on it. Clojure doesn’t have the concept of pointers vs values in the same way as some other languages. All data structures in Clojure are immutable by default, so we don’t need to worry about whether we’re passing a reference or a value.
Next, we’ll look at Clojure’s mechanism for defining abstract behaviors: protocols and multimethods.