Hi all,
Could you please let me know what’s the usual structure when I want a function to return a small number of items?
I’m thinking that the simplest method is to return a vector and then get values using destructuring.
(defn find-product-price []
;; some code
(let [price 111
currency "USD"
discounted false]
[price currency discounted]))
(defn get-message-for-customer []
(let [[price currency discounted] (find-product-price)]
(if discounted
(str "Discount " price " " currency)
(str "The customer will pay " price " " currency))))
(get-message-for-customer)
;; => "The customer will pay 111 USD"
But somewhere (I don’t remember where) I read that getting values from a vector by indexing it is not the proper way. So should I rather use Map? If not how many elements are still OK and how many should rather be returned as a Map?
Thank you.
Best regards,
Paul
This is okay for just two or maybe three “results” but you have to remember the order. It’s more common to return a hash map where your results all have names (and can still be destructured easily):
(defn find-product-price []
;; some code
(let [price 111
currency "USD"
discounted false]
{:price price :currency currency :discounted discounted}))
(defn get-message-for-customer []
(let [{:keys [price currency discounted]} (find-product-price)]
(if discounted
(str "Discount " price " " currency)
(str "The customer will page " price " " currency))))
Returning the named items is slightly more verbose but the destructuring is straightforward – and you can easily have default values now (via :or in the destructuring) – and the rest of the code doesn’t change.
If you really don’t like the verboseness of building a hash map from local bindings, there are any number of utility libraries out there that let you do something like this:
(defn find-product-price []
;; some code
(let [price 111
currency "USD"
discounted false]
(local-map :only :price :currency :discounted)))
;; or just (local-map) if you want all local symbols in it
See, for example: worldsingles/commons: Common utility functions and “extensions” to Clojure (github.com)
I don’t consider it verbose at all. And I actually like it over the proposed vector since I’ll be changing stuff a lot when building my first projects in Clojure and it’s much easier to add a key since adding key doesn’t break API. So yeah, I’m going to use map even for 2 pieces of information.
Thank you @seancorfield , super helpful.
I’ll definitely check this out ;-). Thx!