Maybe Not covers a lot of ground, and I want to explore the declaration of destructuring contexts. What does that mean? Read on to find out!

Let’s explore a specific part of the talk and see how it compared to this shape-based destructuring library of mine called Tracks. Here’s a link to that part of the talk:

Many times only a subset of a map is needed to perform an action. We will discuss two functions: get-movie-times and place-order which both accept the same shape of data, but depend on different pieces of it!

I recreated the example spec from the talk here:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  (ns scratch.select (:require [tracks.core :as t] [clojure.spec.alpha :as s])) (s/def ::street string?) (s/def ::city string?) (s/def ::state string?) (s/def ::zip int?) (s/def ::addr (s/keys :req-un [::street ::city ::state ::zip])) (s/def ::id int?) (s/def ::first string?) (s/def ::last string?) (s/def ::user (s/keys :req-un [::id ::first ::last ::addr]))

Let’s define an example user, and make sure we got it right with s/valid?:

  1 2 3 4 5 6 7 8 9 10 11  (def example-user {:id 1, :first "George", :last "O' Jungle", :addr {:street "123 Lemon Ln.", :city "Chapel Hill", :state "NC", :zip 12345}}) (s/valid? ::user example-user) ;; => true

So, example-user checks out. Now let’s turn to the first function:

## Get Movie Times

This function needs the user-id and the user’s zipcode, which is under the :addr key. We’ll make a toy function that returns a string. Assume this would be doing profitable and heroic work in your effective program.

#### Vanilla - the simplest way

 1 2 3 4 5 6 7 8 9  (defn get-movie-times [user] (str "to get movie times we need: " (:id user) " and " (-> user :addr :zip))) (get-movie-times example-user) ;; => "to get movie times we need: 1 and 12345"

But, it’s more idiomatic to add destructuring.

#### A little desctructuring

 1 2 3 4 5 6  (defn get-movie-times [{:keys [addr id}] (str "to get movie times we need: " id " and " (:zip addr))) (get-movie-times example-user) ;; => "to get movie times we need: 1 and 12345"

This is probably how I would write it - sort of half way between no destructuring and a lot of destructuring.

But why don’t more people (me included) follow through and destruct everything? Isn’t that a better way to describe a destructure context, compared to parsing our function and saying: ‘Wait a second, I only need the :zip of the addr.’?

#### Lots of desctructuring

 1 2 3 4 5 6  (defn get-movie-times [{{zipcode :zip} :addr, user-id :id}] (str "to get movie times we need: " user-id " and " zipcode)) (get-movie-times example-user) ;; => "to get movie times we need: 1 and 12345"

So… on line 2 above, I had to actually google how to do this destructuring. Luckily for us we have an example-user laid out right infront of us, but often that’s not the case! So we need to study the destructuring form - thinking that could be used for better tasks - to figure out what sort of shape to pass in.

(This is the part of the infomercial where there are people struggling with a black and white filter and big red X’s.)

So let’s take a look at how this would be written using my library:

#### Using Tracks

 1 2 3 4 5 6  (t/deftrack get-movie-times-tracks {:id user-id, ;; <--- the shape we need :addr {:zip zipcode}} (str "to get movie times we need: " user-id " and " zipcode)) ;; => "to get movie times we need: 1 and 12345"

Please notice the map that spans lines 2 and 3 above.

Here it is again:

{:id user-id :addr {:zip zipcode}}

That’s just a map with symbols that will be bound to the values found at those positions!

If you know how to write a Clojure map, then with Tracks, you also know how to destructure arbitrarily shaped bits of data.

### Benefits of Tracks

Let me write another function from the talk here:

 1 2 3 4 5 6 7 8 9  (t/deftrack place-order {:first fname, ;; <-- the shape we need :last lname, :addr addr} ;; <-- can (optionally) require all parts of address (str "order placed for: " fname " " lname " \nto: \n" (pr-str addr))) ;; => "order placed for: George O' Jungle to: {:street \"123 Lemon Ln.\", :city \"Chapel Hill\", :state \"NC\", :zip 12345}"

Lines 2-4 are the shape of data that we need from ::user, or the destructuring context. There can be any number of other keys and values and/or collections in the argument to place-order but they will be happily ignored.

Reminder: you can try out Tracks today!

### Benefits of spec/select

Unlike tracks, spec/select can check that the pieces of data you declared are allowed in a clojure spec. I can see that being very useful!

Another interesting thing: In Tracks, the user is required to specify the to be bound, but with spec/select every key is unique – so maybe there can be a convention where:

keyword bound variable
:user/name user-name