Last active
April 20, 2022 15:42
-
-
Save oxalorg/8b8f7026a7c79cbd270b518bbfc8a14e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns poly | |
(:require | |
[clojure.string :as str])) | |
;; ===================================================== | |
;; what is a good way to do polymorphism on an example like this: | |
;; ===================================================== | |
(defn transform-messages [messages] | |
(map #(update % :text str/upper-case) messages)) | |
;; transform-messages expects a list of messages | |
(transform-messages [{:text "hey"} | |
{:text "hello"}]) | |
;; => ({:text "HEY"} {:text "HELLO"}) | |
;; but over the span of months we see this pattern emerge everywhere in the codebase | |
(first | |
(transform-messages [{:text "hey"}])) | |
;; => {:text "HEY"} | |
;; ===================================================== | |
;; simplest approach would be to implement a different function, but that makes | |
;; it even more confusing (maybe? maybe-not?). | |
;; Can we hope to have runtime polymorphism to make a convenient API for the | |
;; caller? | |
;; ===================================================== | |
;; Option 1 | |
;; ===================================================== | |
(defn transform-messages2 [messages] | |
(if-not (sequential? messages) | |
(first | |
(transform-messages [messages])) | |
(map #(update % :text str/upper-case) messages))) | |
(transform-messages2 [{:text "hey"} | |
{:text "hello"}]) | |
;; => ({:text "HEY"} {:text "HELLO"}) | |
(transform-messages2 {:text "hey"}) | |
;; => {:text "HEY"} | |
;; ===================================================== | |
;; Option #2 | |
;; ===================================================== | |
(defprotocol Transformer | |
(transform-messages3 [messages])) | |
(extend-protocol Transformer | |
clojure.lang.Sequential | |
(transform-messages3 [messages] | |
(map #(update % :text str/upper-case) messages)) | |
clojure.lang.IPersistentMap | |
(transform-messages3 [message] | |
(first (transform-messages [message])))) | |
(transform-messages3 [{:text "hey"}]) | |
;; => ({:text "HEY"}) | |
(transform-messages3 {:text "hey"}) | |
;; => {:text "HEY"} | |
;; ===================================================== | |
;; Option #3 | |
;; ===================================================== | |
(defmulti transform-messages4 (fn [messages] | |
(type messages))) | |
(defmethod transform-messages4 clojure.lang.Sequential | |
[messages] | |
(map #(update % :text str/upper-case) messages)) | |
(defmethod transform-messages4 clojure.lang.IPersistentMap | |
[message] | |
(first (transform-messages4 [message]))) | |
(transform-messages4 [{:text "hey"}]) | |
;; => ({:text "HEY"}) | |
(transform-messages4 {:text "hey"}) | |
;; => {:text "HEY"} | |
;; ===================================================== | |
;; Option #4 | |
;; ===================================================== | |
;; something I haven't thought of? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment