; A protocol is a set of methods with no implementations
(defprotocol Fly
"A simple protocol for flying"
(fly [this] "Method to fly"))
; Protocol implementations are checked first for direct definitions (defrecord, deftype, reify),
; then metadata definitions,
; then external extensions (extend, extend-type, extend-protocol)
; impl with defrecord
(defrecord Bird [name]
Fly
(fly [this] (str (:name this) " flies...")))
(def crow (->Bird "Crow"))
(fly crow)
;=> "Crow flies..."
; record can be extended later with extend-type
; record vs. map
; The only difference between a record+protocols and a map+functions is polymorphism.
; If you’re thinking "I need a record and protocols, but I don’t need polymorphism" then the solution is probably a map plus functions.
; deftype: class implement protocol without map-like features, e.g. (:name this) will not work
(deftype Aircraft [name]
Fly
(fly [this] (str (.name this) " flies..")))
(def hurricane (->Aircraft "Hurricane"))
(fly hurricane)
;=> "Hurricane flies.."
; reify: anonymous class implement protocol ~> can’t define fields
(fly (reify Fly
(fly [_] "fly by reify")))
; reify vs. proxy
; reify is Clojure semantics and proxy is Java/host semantics
; extend exiting String type
(extend-protocol Fly
String
(fly [this] (str this " flies..")))
(fly "butterfly")
;=> "butterfly flies.."