Right, and just to take this one step farther, imagine that instead of throwing an error, you wanted to actually return a value. And imagine that your call to MidiSystem/getMidiDeviceInfo might return nil as well, and this is something that needs to be protected against and a value returned accordingly. These sorts of intertwinings of conditional logic and chains of computations is exactly when I reach for better-cond, which would make it look like this: (cond :let [device-info (MidiSystem/getMidiDeviceInfo)]
(nil? device-info) :device-not-available :let [named-device-info (filter #(= (.getName ^MidiDevice$Info %) name) device-info) devices (map #(MidiSystem/getMidiDevice ^MidDevice$Info %) named-device-info) receivables (filter #(>= (.getMaxTransmitters ^MidiDevice %) 0) devices)] (empty? receivables) :no-receivers :let [receivable (first receivables)] (do (.open ^MidiDevice receivable) (.getReceiver ^MidiDevice receivable))) Since you're new to the community, I want to be sure not to mislead you -- the above example is not mainstream Clojure code. But it's a great example of how you can mold the language to suit your own taste of what is readable. The above example is my preferred way to write these sorts of things. On Wed, Sep 28, 2016 at 2:12 PM, <p...@pwjw.com> wrote: > This is a super interesting thread. Thank you all for your input > > I think you are right, @puzzler, that for my case a let may be better. The > original code is above. Using as-> it looks like this (using 'it' as the > name) > > (as-> (MidiSystem/getMidiDeviceInfo) it > (filter #(= (.getName ^MidiDevice$Info %) name) it) > (map #(MidiSystem/getMidiDevice ^MidDevice$Info %) it) > (filter #(>= (.getMaxTransmitters ^MidiDevice %) 0) it) > (if (empty? it) (throw (ex-info "No midi devices with recievers" > {:name name})) it) > (first it) > (do (.open ^MidiDevice it) it) > (.getReceiver ^MidiDevice it) > ) > ) > > using let it looks like this > > (let [device-info (MidiSystem/getMidiDeviceInfo) > named-device-info (filter #(= (.getName ^MidiDevice$Info %) name) > device-info) > devices (map #(MidiSystem/getMidiDevice ^MidDevice$Info > %) named-device-info) > receivables (filter #(>= (.getMaxTransmitters ^MidiDevice > %) 0) devices) > _ (when (empty? receivables) (throw (ex-info "No > midi devices with recievers" {:name name}))) > receivable (first receivables) > result (do > (.open ^MidiDevice receivable) > (.getReceiver ^MidiDevice receivable))] > result) > > and if I were doing a code review, I think I would like the last one > better. > > How very interesting. Thanks all for your constructive answers. What a > great community. > > On Wednesday, September 28, 2016 at 4:47:22 PM UTC-4, puzzler wrote: >> >> A common convention with as-> is to use the symbol $ because it is >> recognized as a Clojure identifier but looks distinctive, so it stands out >> as the placeholder of where to thread. >> >> Personally, when reading code, I don't really like to see long uses of >> the threading operator, and I'd argue that if you find yourself using such >> long chains of computations that the "important" argument is switching to >> different positions, that's a sign that maybe you shouldn't be using >> threading operators in the first place, because it can be hard to mentally >> follow what intermediate data structure you have at each stage of the >> computation. Instead, I'd argue that you should be using `let`, because >> `let` allows you to give each stage of computation a meaningful name, >> making it easy for others (or yourself in two months) to read and reason >> about your code. `let` allows you to communicate intent. >> >> I think one reason people sometimes shy away from using `let` is that it >> can't easily be used at all positions within one's code. For example, if >> you are inside a `cond` doing some conditional logic, adding a `let` means >> you have to also start a new `cond`, and your code ends up awkwardly nested >> and indented, drifting to the right. The better-cond library removes this >> limitation, making it easy to write clear functions which intermingle long >> chains of computations with conditional logic: >> https://github.com/Engelberg/better-cond >> > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.