Does Clojure have an equivalent of Java's try-with-resources construct?
If not, what is the normal way to handle this idiom in Clojure code?
The pre-Java-7 idiom for safely opening and closing resources is verbose enough that they actually added support for try-with-resources to the language. It seems strange to me that I can't find a macro for this use case in the standard Clojure library.
An example to a mainstream Clojure-based project repository—showing how this issue is handled in practice—would be very helpful.
You can use with-open to bind a resource to a symbol and make sure the resource is closed once the control flow left the block.
The following example is from clojuredocs.
(with-open [r (clojure.java.io/input-stream "myfile.txt")]
(loop [c (.read r)]
(when (not= c -1)
(print (char c))
(recur (.read r)))))
This will be expanded to the following:
(let [r (clojure.java.io/input-stream "myfile.txt")]
(try
(loop [c (.read r)]
(when (not= c -1)
(print (char c))
(recur (.read r))))
(finally (.close r))))
You can see that a let block is created with a try-finally to the call .close() method.
you can do something more close to java, making up some macro on top of with-open. It could look like this:
(defmacro with-open+ [[var-name resource & clauses] & body]
(if (seq clauses)
`(try (with-open [~var-name ~resource] ~#body)
~#clauses)
`(with-open [~var-name ~resource] ~#body)))
so you can pass additional clauses alongside the binding.
(with-open+ [x 111]
(println "body"))
expands to simple with-open:
(let*
[x 111]
(try (do (println "body")) (finally (. x clojure.core/close))))
while additional clauses lead to wrapping the it in try-catch:
(with-open+ [x 111
(catch RuntimeException ex (println ex))
(finally (println "finally!"))]
(println "body"))
expands to
(try
(let*
[x 111]
(try (do (println "body")) (finally (. x clojure.core/close))))
(catch RuntimeException ex (println ex))
(finally (println "finally!")))
But still it is quite an opinionated solution.
Related
I'm writing a Clojure wrapper for an object-oriented API that heavily involves resource handling. For instance, for the Foo object, I've written three basic functions: foo?, which returns true iff something is a Foo; create-foo, which attempts to obtain the resources to create a Foo, then returns a map containing a return code and (if the construction succeeded) the newly created Foo; and destroy-foo, which takes a Foo and releases its resources. Here are some stubs for those three functions:
(def foo? (comp boolean #{:placeholder}))
(defn create-foo []
(let [result (rand-nth [::success ::bar-too-full ::baz-not-available])]
(merge {::result result}
(when (= ::success result)
{::foo :placeholder}))))
(defn destroy-foo [foo] {:pre [(foo? foo)]} nil)
Obviously, every time create-foo is called and succeeds, destroy-foo must be called with the returned Foo. Here's a simple example that doesn't use any custom macros:
(let [{:keys [::result ::foo]} (create-foo)]
(if (= ::success result)
(try
(println "Got a Foo:")
(prn foo)
(finally
(destroy-foo foo)))
(do
(println "Got an error:")
(prn result))))
There's a lot of boilerplate here: the try-finally-destroy-foo construct must be present to ensure that all Foo resources are released, and the (= ::success result) test must be present to ensure that nothing gets run assuming a Foo when there is no Foo.
Some of that boilerplate can be eliminated by a with-foo macro, similar to the with-open macro in clojure.core:
(defmacro with-foo [bindings & body]
{:pre [(vector? bindings)
(= 2 (count bindings))
(symbol? (bindings 0))]}
`(let ~bindings
(try
~#body
(finally
(destroy-foo ~(bindings 0))))))
While this does help somewhat, it doesn't do anything about the (= ::success result) boilerplate, and now two separate binding forms are required to achieve the desired result:
(let [{:keys [::result] :as m} (create-foo)]
(if (= ::success result)
(with-foo [foo (::foo m)]
(println "Got a Foo:")
(prn foo))
(do
(println "Got an error:")
(prn result))))
I simply can't figure out a good way to handle this. I mean, I could complect the behaviors of if-let and with-foo into some sort of if-with-foo macro:
(defmacro if-with-foo [bindings then else]
{:pre [(vector? bindings)
(= 2 (count bindings))]}
`(let [{result# ::result foo# ::foo :as m#} ~(bindings 1)
~(bindings 0) m#]
(if (= ::success result#)
(try
~then
(finally
(destroy-foo foo#)))
~else)))
This does eliminate even more boilerplate:
(if-with-foo [{:keys [::result ::foo]} (create-foo)]
(do
(println "Got a Foo:")
(prn foo))
(do
(println "Got a result:")
(prn result)))
However, I don't like this if-with-foo macro for several reasons:
it's very tightly coupled to the specific structure of the map returned by create-foo
unlike if-let, it causes all bindings to be in scope in both branches
its ugly name reflects its ugly complexity
Are these macros the best I can do here? Or is there a more elegant way to handle resource handling with possible resource obtainment failure? Perhaps this is a job for monads; I don't have enough experience with monads to know whether they would be useful tool here.
I'd add an error-handler to with-foo. This way the macro has a focus on what should be done. However, this simplifies the code only when all error-cases are treated by a handful of error handlers. If you have to define a custom error-handler every time you call with-foo this solution makes readability worse than an if-else construct.
I added copy-to-map. copy-to-map should copy all relevant information from the object to a map. This way the user of the macro doesn't by accident return the foo-object, since it gets destroyed inside the macro
(defn foo? [foo]
(= ::success (:result foo)))
(defn create-foo [param-one param-two]
(rand-nth (map #(merge {:obj :foo-obj :result %} {:params [param-one param-two]})
[::success ::bar-too-full ::baz-not-available])))
(defn destroy-foo [foo]
nil)
(defn err-handler [foo]
[:error foo])
(defn copy-to-map [foo]
;; pseudo code here
(into {} foo))
(defmacro with-foo [[f-sym foo-params & {:keys [on-error]}] & body]
`(let [foo# (apply ~create-foo [~#foo-params])
~f-sym (copy-to-map foo#)]
(if (foo? foo#)
(try ~#body
(finally (destroy-foo foo#)))
(when ~on-error
(apply ~on-error [~f-sym])))))
Now you call it
(with-foo [f [:param-one :param-two] :on-error err-handler]
[:success (str "i made it: " f)])
Building from #murphy's excellent idea to put the error handler into with-foo's bindings to keep the focus on the normal case, I've ended up with a solution that I like quite a lot:
(defmacro with-foo [bindings & body]
{:pre [(vector? bindings)
(even? (count bindings))]}
(if-let [[sym init temp error] (not-empty bindings)]
(let [error? (= :error temp)]
`(let [{result# ::result foo# ::foo :as m#} ~init]
(if (contains? m# ::foo)
(try
(let [~sym foo#]
(with-foo ~(subvec bindings (if error? 4 2))
~#body))
(finally
(destroy-foo foo#)))
(let [f# ~(if error? error `(constantly nil))]
(f# result#)))))
`(do
~#body)))
like my if-with-foo macro in the question, this with-foo macro is still tied to the structure returned by create-foo; unlike my if-with-foo macro and #murphy's with-foo macro, it eliminates the need for the user to manually take apart that structure
all names are properly scoped; the user's sym is only bound in the main body, not in the :error handler, and conversely, the ::result is only bound in the :error handler, not in the main body
like #murphy's solution, this macro has a nice, fitting name, instead of something ugly like if-with-foo
unlike #murphy's with-foo macro, this with-foo macro allows the user to provide any init value, rather than forcing a call to create-foo, and doesn't transform the returned value
The most basic use case simply binds a symbol to a Foo returned by create-foo in some body, returning nil if the construction fails:
(with-foo [foo (create-foo)]
["Got a Foo!" foo])
To handle the exceptional case, an :error handler can be added to the binding:
(with-foo [foo (create-foo)
:error (partial vector "Got an error!")]
["Got a Foo!" foo])
Any number of Foo bindings can be used:
(with-foo [foo1 (create-foo)
foo2 (create-foo)]
["Got some Foos!" foo1 foo2])
Each binding can have its own :error handler; any missing error handlers are replaced with (constantly nil):
(with-foo [foo1 (create-foo)
:error (partial vector "Got an error!")
foo2 (create-foo)]
["Got some Foos!" foo1 foo2])
Suppose I use the following code to ensure my code times out:
(defmacro with-timeout [millis & body]
`(let [future# (future ~#body)]
(try
(.get future# ~millis java.util.concurrent.TimeUnit/MILLISECONDS)
(catch java.util.concurrent.TimeoutException x#
(do
(future-cancel future#)
nil)))))
Now I want to make it retry 3 times (if it times out) after a 5 second interval. Do I do it on the TimeoutException - or do I compose it some other way?
My question is: How to execute a function with retries on timeout?
deref has a variant that accepts a timeout. Using this we can implement with-timeout without Java interop.
(defmacro with-timeout [millis & body]
`(loop [tries# 3]
(if (pos? tries#)
(let [future# (future ~#body)
result# (deref future# ~millis ::timeout)]
(if (= result# ::timeout)
(do (future-cancel future#)
(recur (dec tries#)))
result#)))))
(This is not a 100% 'hygienic' because the ::timeout sentinel value could theoretically clash with the value returned by the body forms.)
Here is one solution using core.async. It is quite naive as it does not deal with error handling. I am also not sure if it is exiting the go call cleanly on timeout.
(ns async
(:require [clojure.core.async :as a]))
(defmacro with-timeout [millis & body]
`(loop [tries# 0]
(if (> tries# 3)
(throw (Exception. "Timed out. (3)"))
(let [result# (a/alt!!
(a/go ~#body) ([v# ch] v#)
(a/timeout ~millis) :async/timed-out)]
(if (= result# :async/timed-out)
(recur (inc tries#))
result#)))))
I'm trying to dump the results of a core.async channel to stdout.
Here is what I have (simplified example):
(use 'clojure.core.async)
(def mychan (to-chan (range 100)))
(loop []
(let [a (<!! mychan)]
(if (not (nil? a))
(do
(println a)
(recur)))))
Now I think I should be able to replace this with map:
(map (fn [a] (println a) a) [mychan])
But this seems to be lazy and doesn't return any results.
I can't help but feel that my loop function is somewhat of a workaround. My question is - What is the optimal way to iterate over a core.async channel for printing?
Better use go-loop to run logging process in go block:
(def c (async/chan 10))
(go-loop []
(when-let [msg (<! c)]
(println msg)
(recur)))
(async/onto-chan c (range 100))
or you can use transducers on 1.7
(def prn-chan (async/chan 10 (map println)))
(async/onto-chan prn-chan (range 100))
I have a Ring handler which uses several functions to build the response. If any of these functions throw an exception, it should be caught so a custom response body can be written before returning a 500.
I'm writing the unit test for the handler, and I want to ensure that an exception thrown by any of these functions will be handled as described above. My instinct was to use with-redefs inside a doseq:
(doseq [f [ns1/fn1 ns1/fn2 ns2/fn1]]
(with-redefs [f (fn [& args] (throw (RuntimeException. "fail!"))]
(let [resp (app (request :get "/foo")))))]
(is (= (:status resp) 500))
(is (= (:body resp) "Something went wrong")))))
Of course, given that with-redefs wants to change the root bindings of vars, it is treating f as a symbol. Is there any way to get it to rebind the var referred to by f? I suspect that I'm going to need a macro to accomplish this, but I'm hoping that someone can come up with a clever solution.
with-redefs is just sugar over repeated calls to alter-var-root, so you can just write the desugared form yourself, something like:
(doseq [v [#'ns1/fn1 #'ns1/fn2 #'ns2/fn1]]
(let [old #v]
(try
(alter-var-root v (constantly (fn [& args]
(throw (RuntimeException. "fail!")))))
(let [resp (app (request :get "/foo")))
(is (= (:status resp) 500))
(is (= (:body resp) "Something went wrong")))
(finally (alter-var-root v (constantly old))))))
Following on from amalloy's great answer, here's a utility function that I wrote to use in my tests:
(defn with-mocks
"Iterates through a list of functions to-mock, rebinding each to mock-fn, and calls
test-fn with the optional test-args.
Example:
(defn foobar [a b]
(try (+ (foo a) (bar b))
(catch Exception _ 1)))
(deftest test-foobar
(testing \"Exceptions are handled\"
(with-mocks
[#'foo #'bar]
(fn [& _] (throw (RuntimeException. \"\")))
(fn [a b] (is (= 1 (foobar a b)))) 1 2)))"
[to-mock mock-fn test-fn & test-args]
(doseq [f to-mock]
(let [real-fn #f]
(try
(alter-var-root f (constantly mock-fn))
(apply test-fn test-args)
(finally
(alter-var-root f (constantly real-fn)))))))
Clojure 1.5 introduced clojure.edn, which includes a read function that requires a PushbackReader.
If I want to read the first five objects, I can do:
(with-open [infile (java.io.PushbackReader. (clojure.java.io/reader "foo.txt"))]
(binding [*in* infile]
(let [edn-seq (repeatedly clojure.edn/read)]
(dorun (take 5 (map println edn-seq))))))
How can I instead print out all of the objects? Considering that some of them may be nils, it seems like I need to check for the EOF, or something similar. I want to have a sequence of objects similar to what I would get from line-seq.
Use :eof key
http://clojure.github.com/clojure/clojure.edn-api.html
opts is a map that can include the following keys: :eof - value to
return on end-of-file. When not supplied, eof throws an exception.
edit: sorry, that wasn't enough detail! here y'go:
(with-open [in (java.io.PushbackReader. (clojure.java.io/reader "foo.txt"))]
(let [edn-seq (repeatedly (partial edn/read {:eof :theend} in))]
(dorun (map println (take-while (partial not= :theend) edn-seq)))))
that should do it
I looked at this again. Here is what I came up with:
(defn edn-seq
"Returns the objects from stream as a lazy sequence."
([]
(edn-seq *in*))
([stream]
(edn-seq {} stream))
([opts stream]
(lazy-seq (cons (clojure.edn/read opts stream) (edn-seq opts stream)))))
(defn swallow-eof
"Ignore an EOF exception raised when consuming seq."
[seq]
(-> (try
(cons (first seq) (swallow-eof (rest seq)))
(catch java.lang.RuntimeException e
(when-not (= (.getMessage e) "EOF while reading")
(throw e))))
lazy-seq))
(with-open [stream (java.io.PushbackReader. (clojure.java.io/reader "foo.txt"))]
(dorun (map println (swallow-eof (edn-seq stream)))))
edn-seq has the same signature as clojure.edn/read, and preserves all of the existing behavior, which I think is important given that people may use the :eof option in different ways. A separate function to contain the EOF exception seemed like a better choice, though I'm not sure how best to capture it since it shows up just as a java.lang.RuntimeException.