3
votes

I keep seeing this macro <?, in swanodette's code which looks really useful :

In this gist :

;; BOOM!!! we can convert async errors into exceptions
(go (try
      (let [x (<? (run-task (.-readFile fs) "foo.txt" "utf8"))]
        (.log js/console "Success" x))
      (catch js/Error e
        (.log js/console "Oops" e))))

In this blog post :

(go (try
      (let [tweets    (<? (get-tweets-for "swannodette"))
            first-url (<? (expand-url (first (parse-urls tweets))))
            response  (<? (http-get first-url))]
        (. js/console (log "Most recent link text:" response)))
      (catch js/Error e
        (. js/console (error "Error with the twitterverse:" e)))))

<? is just a touch of macro sugar that expands into something like (throw-err (<! [expr])). In core.async <! serves the same purpose as ES6's yield operator. If an asynchronous process writes an error onto its channel we will convert it into an exception.

But I can't find a definition for it. How is it implemented in Clojure{Script} ?

1
FYI: All his code is on github: github.com/swannodette/swannodette.github.com File you're looking for: macros.clj & helpers.cljsClojureMostly
@Andre thanks ! I was looking for that ! (Searching <? on github doesn't work)nha

1 Answers

1
votes

Alright so here is what I am using so far. There is probably room for improvement.

In Clojure :

(defn throw-err [e]
  (when (instance? Throwable e) (throw e))
  e)

(defmacro <? [ch]
  `(throw-err (<! ~ch)))

In ClojureScript :

(defn error? [x]
  (instance? js/Error x))


(defn throw-err [e]
  (when (error? e) (throw e))
  e)

(defmacro <? [ch]
  `(throw-err (<! ~ch)))

I am completely unsure about the readability of my solution though (throw-err looks like it should throw an error, but it doesn't. At least not every time).