typestar

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

  1. (defprotocol Billable opens the declaration, and (monthly-cost [this] "Charge in dollars for one month.") names the operation without implementing it.
  2. (defrecord Metered [rate units] lists the fields, and the Billable line beneath it begins an inline implementation.
  3. (doseq [account accounts] calls (monthly-cost account) over both records, and each type runs its own body.

Keywords and builtins used here

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.

Type this snippet

Step 3 of 3 in State & records, step 24 of 27 in Language basics.

← Previous Next →