Hello Clojurists,
I’m learning Clojure and best way to learn is to try it out. I’m slightly confused about Protocols so I decided to write the following code.
Could you please take a look and tell me is this the primary use case for using Protocols (except performance reasons)? Are there any other use cases?
To explain what I’m doing:
- I have a protocol
Uri
and a recordPath
(I could have another recordUrl
since from terminology perspective bothUrl
andPath
are subset ofUri
) -
Path
can be both in the form of plain text (string) or data structure (record) that holds additional details. - Btw. I’m not trying to write URI library - this is really just for testing and I don’t like examples with cars ;-).
Thank you.
Adam
(defn cut-string [s max-length]
(if (> (count s) max-length)
(subs s 0 max-length)
s))
(defprotocol Uri
(convert-to-string [this])
(convert-to-string-with-max-length [this max-length])
(get-length [this]))
(defrecord Path [value separator relative]
Uri
(convert-to-string [this]
(:value this))
(convert-to-string-with-max-length [this max-length]
(cut-string (:value this) max-length))
(get-length [this]
(count (:value this))))
(extend-protocol Uri
String
(convert-to-string [this]
this)
(convert-to-string-with-max-length [this max-length]
(cut-string this max-length))
(get-length [this]
(count this)))
(def some-path (Path. "/some/path", "/", false))
; ####################### using protocols #######################
(convert-to-string some-path)
;; => "/some/path"
(convert-to-string-with-max-length some-path 8)
;; => "/some/pa"
(get-length some-path)
;; => 10
(convert-to-string "different/path")
;; => "different/path"
(convert-to-string-with-max-length "different/path" 5)
;; => "diffe"
(get-length "different/path")
;; => 14
; ####################### using multimethod #######################
(defn get-uri-type [uri & _]
(cond
(string? uri) :plain
(map? uri) :with-details))
(defmulti multimethod-convert-to-string get-uri-type)
(defmethod multimethod-convert-to-string :plain [uri]
uri)
(defmethod multimethod-convert-to-string :with-details [uri]
(:value uri))
(defmulti multimethod-convert-to-string-with-max-length get-uri-type)
(defmethod multimethod-convert-to-string-with-max-length :plain [uri max-length]
(cut-string uri max-length))
(defmethod multimethod-convert-to-string-with-max-length :with-details [uri max-length]
(cut-string (:value uri) max-length))
(defmulti multimethod-get-length get-uri-type)
(defmethod multimethod-get-length :plain [uri]
(count uri))
(defmethod multimethod-get-length :with-details [uri]
(count (:value uri)))
(multimethod-convert-to-string some-path)
;; => "/some/path"
(multimethod-convert-to-string-with-max-length some-path 3)
;; => "/so"
(multimethod-get-length some-path)
;; => 10
(multimethod-convert-to-string "different/path")
;; => "different/path"
(multimethod-convert-to-string-with-max-length "different/path" 11)
;; => "different/p"
(multimethod-get-length "different/path")
;; => 14