Protocols and records in Clojure
Declares a billing operation once as a protocol and lets two record types answer it differently.
;; A protocol names operations without saying how a type carries
;; them out. A record is a map with named fields, and it can satisfy
;; the protocol inline with its own method body.
(defprotocol Billable
(monthly-cost [this] "Charge in dollars for one month."))
(defrecord Metered [rate units]
Billable
(monthly-cost [this] (* rate units)))
(defrecord Flat [fee]
Billable
(monthly-cost [this] fee))
;; Callers name only the protocol; the record picks the behavior.
(def accounts [(->Metered 0.14 320) (->Flat 45.0)])
(doseq [account accounts]
(println (format "%-8s %7.2f" (.getSimpleName (class account))
(monthly-cost account))))
How it works
(defprotocol Billableopens the declaration, and(monthly-cost [this] "Charge in dollars for one month.")names the operation without implementing it.(defrecord Metered [rate units]lists the fields, and theBillableline beneath it begins an inline implementation.(doseq [account accounts]calls(monthly-cost account)over both records, and each type runs its own body.
Keywords and builtins used here
classdefdefprotocoldefrecorddoseqformatprintln
The run, in numbers
- Lines
- 19
- Characters to type
- 635
- Tokens
- 90
- Three-star pace
- 70 tpm
At the three-star pace of 70 tokens a minute, this run takes about 77 seconds.
Step 3 of 3 in State & records, step 24 of 27 in Language basics.