Did you know about -> and ->>?

This is the second post in my „Did you know?“ series. This time we will have a closer look at -> and ->> .

From `->` to `->>` and back again

We all know the two threading forms which help a lot with chains of calls. -> threads on the first position, ->> on the last. Here some examples.

( -> a b ( c d ) ( e f ) g ) ( g ( e ( c ( b a ) d ) f ) ) ( ->> a b ( c d ) ( e f ) g ) ( g ( e f ( c d ( b a ) ) ) )

Sometimes you have one or two one calls in the middle of the chain which require the other form. Then one has to split the chain.

( let [ first-part ( -> a b ( c d ) ) second-part ( ->> first-part ( map h ) ( filter pred ) ) ] ( -> second-part ( e f ) g ) )

However, we can actually simplify this!

( -> a b ( c d ) ( ->> ( map f ) ( filter pred ) ) ( e f ) g )

Going the other way around is not so trivial. Trying the naive approach we get the following.

( ->> x ( map f ) ( -> ( get :x ) ) ( filter pred ) ) ( filter pred ( map ( get :x ) f x ) )

Not quite what we want. The reason is, that ->> inserts the expression at the end of the next form. This is also the case for the contained -> form. And from there on things go southwards.

However with a small trick, we can still get what we want: we simply have to start with -> .

( -> a ( ->> ( map h ) ( filter pred ) ) ( c d ) ( e f ) ( ->> ( remove second-pred ) ( reduce i ) ) )

Here is a practical example (allthough a little stretched): a column index to Excel column converter.

user=> ( def column-chars "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) #' user/column-chars user=> ( defn index-to-column [ idx ] ( ->> idx ( iterate # ( -> % dec ( quot 26 ) ) ) ( take-while ( complement zero? ) ) ( map # ( -> % dec ( rem 26 ) ( ->> ( nth column-chars ) ) ) ) reverse ( apply str ) ) ) #' user/index-to-column user=> ( index-to-column 1 ) "A" user=> ( index-to-column 26 ) "Z" user=> ( index-to-column 27 ) "AA" user=> ( index-to-column 677 ) "ZA"

Did you also know about `doto`?

And finally – as a small teaser that there is more to explore – there is also doto . Consider this Swing example.

( doto ( JFrame. ) ( .setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE ) ( -> .getContentPane ( .add ( JButton. "Hello" ) ) ) ( .setVisible true ) )

There is a lot to explore in Clojure. Go on and experiment!