I have some Java code that I would write like this:
String var1;
String var2;
int var3;
try {
String var1 = func1_that_might_throw();
String var2 = func2_that_might_throw();
int var3 = func3_that_might_throw();
do_something_that_might_throw(var1, var2, var3);
} catch (Exception e) {
cleanup_resources(var1, var2, var3);
}
Turning this into Clojure is a nightmare.
(try+
(let [var1 (func1_that_might_throw)
var2 (func2_that_might_throw)
var3 (func3_that_might_throw)]
(do_something_that_might_throw var1 var2 var3))
(catch Exception e
(cleanup_resources var1 var2 var3)))
The problem is var1, var2, var3 don't exist in the catch block.
Moving the let to outside of try is problematic because functions 1 through 3 might throw and needs to be caught and resources cleaned up.
What I think I might need is just three placeholder variables outside of try, but a) I don't even know if clojure allows this, and b) makes everything more complicated. I don't think this is how a veteran would do this in clojure. What's the solution here?
Ref/Atom
Without using dynamic variables, you can also put your data into boxes:
(let [v1 (ref nil)
v2 (ref nil)
v3 (ref nil)]
(try
(dosync
(ref-set v1 (f1))
(ref-set v2 (f2))
(ref-set v3 (f3))
(do-something #v1 #v2 #v3))
(catch Exception e
(cleanup-resources #v1 #v2 #v3))))
Finally
If however you are committed to go the purely immutable way, here is what you should write:
(let [v1 (func1)]
(try
(let [v2 (func2)]
(try
(let [v3 (func3)]
(try
(do
(try
(do-something v1 v2 v3)
(catch Exception e <error-handling>)))
(finally (cleanup-3 v3))))
(finally (cleanup-2 v2))))
(finally (cleanup-1 v1))))
You can see that cleanup-resources is split into three functions, which in my opinion would make sense also in your Java code in the first place.
The above was generated using a macro:
(defmacro with-cleanups [bindings & body]
(reduce
(fn [form [v value cleanup]]
`(let [~v ~value]
(try ~form
(finally ~cleanup))))
`(do ~#body)
(reverse (partition 3 bindings))))
Here is the actual code that you need to write:
(with-cleanups [v1 (func1) (cleanup-1 v1)
v2 (func2) (cleanup-2 v2)
v3 (func3) (cleanup-3 v3)]
(try
(do-something v1 v2 v3)
(catch Exception e <error-handling>)))
If you prefer, you could let the cleanup part of the bindings be a function instead of an expression:
(with-cleanups [v1 (func1) cleanup-1
v2 (func2) cleanup-2
v3 (func3) cleanup-3]
(try
(do-something v1 v2 v3)
(catch Exception e <error-handling>)))
This is very much a question of program design and structure. It sounds like a chicken-and-egg problem regarding resource state management. Rather then solve this problem it's likely to be much less painful if you can break that problem down into :
a function that creates your state and handles errors in creating the state
another function that does the work and handles the errors caused while doing the work.
These are separate problems being solved by one function. Things tend to get easier if you can pry these things apart.
Now, with the preaching aside, clojure has many ways of handling mutable state, and does not pretend that the whole world can be convinced to do things "the right way", and Clojure does allow you to simply create and set variables just line in java. The reason you never see these in practice is because they are always a sign that the problem is being solved in a backwards way or is being mixed with another different problem.
TRY EVERYTHING YOU CAN TO AVOID WRITING CODE LIKE THIS:
user> (def ^:dynamic var1)
#'user/var1
user> (def ^:dynamic var2)
#'user/var2
user> (def ^:dynamic var3)
#'user/var3
user> (defn do-stuff []
(binding [var1 nil
var2 nil
var3 nil]
(try
(set! var1 42)
(set! var2 43)
(set! var3 44)
(+ var1 var2 var3)
(catch Exception e
e))))
#'user/do-stuff
user> (do-stuff)
129
I have never seen code like this used in any practical problem (I've been writing Clojure as my day job about as long as anyone) and these things basically never come up. I'm wirting it here because I don't want people comming away with the impression that there are things you "can't write" in Clojure.
It's important to emphasize that this code has all the concurrency safeties that the rest of clojure has. Because binding creates thread local values that follow this code while isolating other users of var1, var2, etc. unaffected.
One more resonable way of doing this is to use futures (delay creates these) to define the computation to be run outside the try-catch, without actually running it
Then the code enters a try catch block and derefrences the delayed code which causes it to actually run.
user> (defn do-stuff []
(let [var1 (delay (inc 41))
var2 (delay (dec 43))
var3 (delay (/ 42 0))]
(try
(+ #var1 #var2 #var3)
(catch Exception e
(println "cleaning up: " var1 var2 var3)))))
#'user/do-stuff
user> (do-stuff)
cleaning up: #object[clojure.lang.Delay 0x3c55d284 {:status :ready, :val 42}]
#object[clojure.lang.Delay 0x7bfa6dd1 {:status :ready, :val 42}]
#object[clojure.lang.Delay 0x5e9e285b {:status :failed, :val #error {
:cause Divide by zero
This assumes you can change your cleanup code to take a reference to something that may contain either a value to cleanup, or the exception that caused the error. delays have the useful property that the exception can be thrown in the main function, and then be thrown again in the error handler. Ponder this example:
user> (def x (delay (/ 2 0)))
#'user/x
user> #x
ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:158)
user> #x
ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:158)
You should certainly solve this problem by breaking your function into two, and not by using set! on dyanamic vars. It's just possible.
You can write this kind of code simply in Java and Clojure in the same way. For every function that might cause an exception have that exception as part of the return value. In Java you would return an instance of a class that would have for example a getErrors() method. In Clojure you could return a hash-map or possibly a tuple-2 vector. The hash-map could for example contain the exception: {:exception nil} You would need to do this with all of 4 your functions: do_something_that_might_throw and the other three.
In Clojure you can then map/filter over the results. Exceptions can be handled when they need to be (locally, or as in your case collectively (but still quite locally)) and not proliferate throughout the codebase.
update: refactored macro to take code blocks instead of functions
like #coredump, i would also propose a macro for that, but it's closer to the op's variant (in which he cleans up all the resources in one block):
(defmacro with-resources [[var expr & other :as resources]
body cleanup-block
[error-name error-block :as error-handler]]
(if (empty? resources)
`(try ~body
(catch Throwable e#
(let [~error-name e#] ~error-block))
(finally ~cleanup-block))
`(try
(let ~[var expr]
(with-resources ~other ~body ~cleanup-block ~error-handler))
(catch Throwable e#
(let ~(vec (interleave (take-nth 2 resources)
(repeat nil)))
~cleanup-block
(let [~error-name e#] ~error-block))))))
this is how it works:
it initializes the resources, and if something is thrown from initializers or body if executes cleanup-block with all resources (or nils for uninitialized ones), and error-block with an exception bind to the error-name, and returns its value. It nothing throws, just calls the cleanup-block and returns the value of body.
examples:
user> (with-resources [a 100 b 200 c 300]
;;body
(+ a b c)
;;cleanup
(println "cleanup:" :a a :b b :c c)
;;error handler
(error (do (println "Error caught:" (.getMessage error))
:error)))
cleanup: :a 100 :b 200 :c 300
600
user> (with-resources [a (throw (Exception. "A THROWS")) b 200 c 300]
;;body
(+ a b c)
;;cleanup
(println "cleanup:" :a a :b b :c c)
;;error handler
(error (do (println "Error caught:" (.getMessage error))
:error)))
cleanup: :a nil :b nil :c nil
Error caught: A THROWS
:error
user> (with-resources [a 100 b (throw (Exception. "B THROWS")) c 300]
;;body
(+ a b c)
;;cleanup
(println "cleanup:" :a a :b b :c c)
;;error handler
(error (do (println "Error caught:" (.getMessage error))
:error)))
cleanup: :a 100 :b nil :c nil
Error caught: B THROWS
:error
user> (with-resources [a 100 b 200 c (throw (Exception. "C THROWS"))]
;;body
(+ a b c)
;;cleanup
(println "cleanup:" :a a :b b :c c)
;;error handler
(error (do (println "Error caught:" (.getMessage error))
:error)))
cleanup: :a 100 :b 200 :c nil
Error caught: C THROWS
:error
user> (with-resources [a 100 b 200 c 300]
;;body
(throw (Exception. "BODY THROWS"))
;;cleanup
(println "cleanup:" :a a :b b :c c)
;;error handler
(error (do (println "Error caught:" (.getMessage error))
:error)))
Error caught: BODY THROWS
cleanup: :a 100 :b 200 :c 300
:error
Related
This is a bit similar to this question, but I want to catch multiple exceptions and handle them all the same. In Ruby, I can write
begin
rand(2) == 0 ? ([] + '') : (foo)
rescue TypeError, NameError => e
puts "oops: #{e.message}"
end
Can I do the same in Clojure? For now I let a function and just call it in each catch body.
(ns mastering.stackoverflow
(:use
[slingshot.slingshot :only [try+]]))
(try+
; ...
(catch (comp #{TypeError NameError} class) _ "caught"))
The slingshot library is available on github.
You could also delegate to a local function, although it gets a little verbose:
(let [handle #(println %)]
(try
(throwing-op)
(catch TypeError e (handle e))
(catch NameError e (handle e))))
There is no simple built-in solution for that yet, however, there is an open ticket.
You can write a dispatch on type in the catch block by hand.
(try
(do-dangerous-operation-here)
(catch Exception e
(condp (fn [cs t] (some #(instance? % t) cs)) e
[IllegalStateException IllegalArgumentException]
(println "Either illegal state or illegal argument!")
[java.sql.SQLException]
(println "Sql error!")
;; whe pass through the exception when not handled
(throw e))))
You can also use this macro:
(defmacro try*
"Macro to catch multiple exceptions with one catch body.
Usage:
(try*
(println :a)
(println :b)
(catch* [A B] e (println (class e)))
(catch C e (println :C))
(finally (println :finally-clause)))
Will be expanded to:
(try
(println :a)
(println :b)
(catch A e (println (class e)))
(catch B e (println (class e)))
(catch C e (println :C))
(finally (println :finally-clause)))
"
[& body]
(letfn [(catch*? [form]
(and (seq form)
(= (first form) 'catch*)))
(expand [[_catch* classes & catch-tail]]
(map #(list* 'catch % catch-tail) classes))
(transform [form]
(if (catch*? form)
(expand form)
[form]))]
(cons 'try (mapcat transform body))))
credits https://gist.github.com/Gonzih/5814945
In Clojure, is there a way to make a var constant such that it can be used in case statements?
e.g.
(def a 1)
(def b 2)
(let [x 1]
(case x
a :1
b :2
:none))
=> :none
I understand I can use something like cond or condp to get around this, but it would be nice if I could define something that does not require further evaluation so I could use case.
Related and answer stolen from it:
As the docstring tells you: No you cannot do this. You can use Chas Emericks macro and do this however:
(defmacro case+
"Same as case, but evaluates dispatch values, needed for referring to
class and def'ed constants as well as java.util.Enum instances."
[value & clauses]
(let [clauses (partition 2 2 nil clauses)
default (when (-> clauses last count (== 1))
(last clauses))
clauses (if default (drop-last clauses) clauses)
eval-dispatch (fn [d]
(if (list? d)
(map eval d)
(eval d)))]
`(case ~value
~#(concat (->> clauses
(map #(-> % first eval-dispatch (list (second %))))
(mapcat identity))
default))))
Thus:
(def ^:const a 1)
(def ^:const b 2)
(let [x 1]
(case+ x
a :1
b :2
:none))
=> :1
An alternative (which is nice since it's more powerful) is to use core.match's functionality. Though you can only match against local bindings:
(let [x 2
a a
b b]
(match x
a :1
b :2
:none))
=> :2
You can also use clojure.core/condp for the job:
(def a 1)
(def b 2)
(let [x 1]
(condp = x
a :1
b :2
:none))
#=> :1
(defrecord Sample (x y))
(def check (Sample. 1 2))
(:x check) ;returns 1
If I receive (:x check) as an argument to a function, is there a way to access check? Or, in other words, return
#:user.Sample{:x 1, :y 2}
No, if a function is passed (:x check) as parameter then the value was already evaluated before entering the function, you'll just receive a 1 as value, and you can't retrieve the record it came from.
If you need the record inside the function, why don't you pass check as parameter?
As Óscar described, (:x check) won't work because its result is 1, and '(:x check) won't work because its result is a list containing the keyword :x and the symbol check.
However, instead of using quote you could use the list function:
(defn receiver [arg]
(map class arg))
;; With a quoted list it receives the symbol `check` rather
;; than the Sample record
(receiver '(:x check))
;=> (clojure.lang.Keyword clojure.lang.Symbol)
;; But this way it does receive the Sample
(receiver (list :x check))
;=> (clojure.lang.Keyword user.Sample)
And (list :x check) can be evaluated:
(eval (list :x check))
;=> 1
(defn receiver [arg]
(str "received " arg "; eval'd to: " (eval arg)))
(receiver (list :x check))
;=> "received (:x #user.Sample{:x 1, :y 2}); eval'd to: 1"
The reason that quote and list behave so differently is that quote doesn't evaluate it's argument. And, when a list is quoted, that effect is recursive: none of the items in the list are evaluated either.
There's another type of quote, called syntax-quote or backquote (and described on the Clojure.org page about the reader) which allows you to selectively un-quote (i.e. evaluate) items.
(require '[clojure.pprint])
(let [n 1
x :x
c check]
(clojure.pprint/pprint
(vector `(n x c)
`(~n x c)
`(~n ~x c)
`(~n ~x ~c))))
Prints:
[(user/n user/x user/c)
(1 user/x user/c)
(1 :x user/c)
(1 :x {:x 1, :y 2})]
And, actually, I lied a little bit. You could in fact use '(:x check) in this particular case. resolve will return the Var associated with a symbol, and deref (or its # reader macro) will get you the Var's value.
(resolve 'check)
;=> #'user/check
(deref (resolve 'check))
;=> #user.Sample{:x 1, :y 2}
(defn resolve-and-deref-symbols [form]
(map (fn [x] (if (symbol? x)
#(resolve x)
x))
form))
(defn receiver [arg]
(str "received " arg "; eval'd to: " (eval (resolve-and-deref-symbols arg))))
(receiver '(:x check))
;=> "received (:x check); eval'd to: 1"
I didn't mention it straight-away because, while it works easily enough in this example, it's not at all appropriate for the general case. (For instance, it won't work with locals, and handling namespaces and nested data structure would be painful).
I'm getting unexpected behaviour in some monads I'm writing.
I've created a parser-m monad with
(def parser-m (state-t maybe-m))
which is pretty much the example given everywhere (here, here and here)
I'm using m-plus to act as a kind of fall-through query mechanism, in my case, it first reads values from a cache (database), if that returns nil, the next method is to read from "live" (a REST call).
However, the second value in the m-plus list is always called, even though its value is disgarded (if the cache hit was good) and the final return is that of the first monadic function.
Here's a cutdown version of the issue i'm seeing, and some solutions I found, but I don't know why.
My questions are:
Is this expected behaviour or a bug in m-plus? i.e. will the 2nd method in a m-plus list always be evaluated even if the first item returns a value?
Minor in comparison to the above, but if i remove the call
_ (fetch-state) from checker, when i evaluate that method, it
prints out the messages for the functions the m-plus is calling
(when i don't think it should). Is this also a bug?
Here's a cut-down version of the code in question highlighting the problem. It simply checks key/value pairs passed in are same as the initial state values, and updates the state to mark what it actually ran.
(ns monads.monad-test
(:require [clojure.algo.monads :refer :all]))
(def parser-m (state-t maybe-m))
(defn check-k-v [k v]
(println "calling with k,v:" k v)
(domonad parser-m
[kv (fetch-val k)
_ (do (println "k v kv (= kv v)" k v kv (= kv v)) (m-result 0))
:when (= kv v)
_ (do (println "passed") (m-result 0))
_ (update-val :ran #(conj % (str "[" k " = " v "]")))
]
[k v]))
(defn filler []
(println "filler called")
(domonad parser-m
[_ (fetch-state)
_ (do (println "filling") (m-result 0))
:when nil]
nil))
(def checker
(domonad parser-m
[_ (fetch-state)
result (m-plus
;; (filler) ;; intitially commented out deliberately
(check-k-v :a 1)
(check-k-v :b 2)
(check-k-v :c 3))]
result))
(checker {:a 1 :b 2 :c 3 :ran []})
When I run this as is, the output is:
> (checker {:a 1 :b 2 :c 3 :ran []})
calling with k,v: :a 1
calling with k,v: :b 2
calling with k,v: :c 3
k v kv (= kv v) :a 1 1 true
passed
k v kv (= kv v) :b 2 2 true
passed
[[:a 1] {:a 1, :b 2, :c 3, :ran ["[:a = 1]"]}]
I don't expect the line k v kv (= kv v) :b 2 2 true to show at all. The final result is the value returned from the first function to m-plus, as I expect, but I don't expect the second function to even be called.
Now, I've found if I pass a filler into m-plus that does nothing (i.e. uncomment the (filler) line) then the output is correct, the :b value isn't evaluated.
If I don't have the filler method, and make the first method test fail (i.e. change it to (check-k-v :a 2) then again everything is good, I don't get a call to check :c, only a and b are tested.
From my understanding of what the state-t maybe-m transformation is giving me, then the m-plus function should look like:
(defn m-plus
[left right]
(fn [state]
(if-let [result (left state)]
result
(right state))))
which would mean that right isn't called unless left returns nil/false.
Edit:
After looking at state-t and maybe-m source, the m-plus looks more like:
(fn [& statements]
(fn [state]
(apply (fn [& xs]
(first (drop-while nil? xs)))
(map #(% state) statements))))
But the principle is the same, (first (drop-while nil? ...) should only execute over the items that return a valid value.
I'd be interested to know if my understanding is correct or not, and why I have to put the filler method in to stop the extra evaluation (whose effects I don't want to happen).
Edit:
If I switch over to using Jim Duey's hand written implementation of parser-m (from his excellent blogs), there is no evaluation of the second function in m-plus, which seems to imply the transformation monad is breaking m-plus. However, even in this implementation, if I remove the initial (fetch-state) call in the checker function, the domonad definition causes the output of the creation of the m-plus functions, suggesting something going on in domonad's implementation I'm not expecting.
Apologies for the long winded post!
Say I have a map of this form:
(def m {:a "A" :b "B"})
and I want to do something if :a and :b are both not nil, I can do:
(if-let [a (:a m)]
(if-let [b (:b m)]
... etc ))
or
(if (and (:a m) (:b m))
(let [{a :a b :b} m]
... etc ))
or even
(if (every? m [:a :b])
(let [{a :a b :b} m]
... etc ))
Is there a neater (ie one-line) way to achieve this?
I think a macro may be necessary here to create the behavior you want. I have never written one (yet) but the following representation suggests to me that this might be fairly straightforward:
(let [{:keys [a b]} m]
(when (every? identity [a b])
(println (str "Processing " a " and " b))))
Using the :keys form of destructuring binding and every? enables a single specification of a vector of keys to destructure and check, and the bound locals are available in a following code block.
This could be used to make a macro such as (when-every? [keys coll] code-with-bindings)
I may update this answer with the macro code if I can take the time to work out how to do it.
You could use map destructuring -- a useful feature of Clojure. This also exploits the facts that and is short-circuiting, and any key in the first map not found in the second map gets nil, a falsy value:
(let [{a :a b :b} {:a 1 :b "blah"}]
(and a b (op a b)))
Okay, so it's two lines instead of one .... also this doesn't distinguish between nil and other falsy values.
not-any? is a nice shortcut for this:
user> (not-any? nil? [(m :a) (m :b)])
true
user> (not-any? nil? [(m :a) (m :b) (m :d)])
false
user>
I am not quite sure what you want to do if the keys have non-nil values or whether you want non-nil keys or values returned. So, I just solved it for non-nil keys being returned.
You'd use the following as an intermediate step as part of a final solution.
I'm showing all the steps I used, not to be pedantic, but to provide a complete answer. The namespace is repl-test. It has a main associated with it.
repl-test.core=> (def m {:a "A" :b "B" :c nil})
#'repl-test.core/m
repl-test.core=> (keys m)
(:a :c :b)
and then finally:
; Check key's value to determine what is filtered through.
repl-test.core=> (filter #(if-not (nil? (%1 m)) (%1 m)) (keys m) )
(:a :b)
By the way I found an ugly one-liner, which works because and returns the last thing in its argument list if they're all true:
(if-let [[a b] (and (:a m) (:b m) [(:a m)(:b m)])]
(println "neither " a " nor " b " is falsey")
(println "at least one of " a " or " b " is falsey"))