I look forward to pre/post conditions becoming more helpful. Truss is a good example of how things can improve. I think part of the challenge is not making the code too messy.
Here's a proof of concept of how metadata in the pre/post/assert expression could be used to craft nice messages: (defn get-highlander [hs] {:pre [^{:msg "There can be only one"} (= 1 (count ^:var hs))]} (first hs)) And the error messages can be presented as: user=> (get-highlander ["asdf" "ss"]) AssertionError Assert failed: There can be only one (= 1 (count hs)) where hs is ["asdf" "ss"] user/get-highlander (NO_SOURCE_FILE:4) This works by modifying the assert macro so it works for general asserts too (assert (test (complex (form (with (a ^:var varible))))) "bad variable") The modifications to assert seem quite modest but I'm unsure if this is an approach which is considered to be the correct solution. (declare tree-seq) (defn pr-vars [form env] (let [var? (fn [x] (-> x meta :var))] (for [var (filter var? (tree-seq seq? identity form))] `(str "\n where " '~var " is " (pr-str ~var))))) (defmacro assert "Evaluates expr and throws an exception if it does not evaluate to logical tru" {:added "1.0"} ([x] (when *assert* `(when-not ~x (throw (new AssertionError (str "Assert failed: " ~(or (-> x meta :msg) "") "\n" (pr-str '~x) ~@(pr-vars x &env))))))) ([x message] (when *assert* `(when-not ~x (throw (new AssertionError (str "Assert failed: " ~message "\n" (pr-str '~x) ~@(pr-vars x &env)))))))) On Thursday, 31 March 2016 03:09:03 UTC+11, Niels van Klaveren wrote: > > Truss <https://github.com/ptaoussanis/truss>also has good support for :pre > and :post conditions > <https://github.com/ptaoussanis/truss#assertions-within-prepost-conditions> > > On Monday, July 11, 2011 at 7:40:48 PM UTC+2, frye wrote: >> >> Note: This message was originally posted by ' Shantanu' on the "*Re: >> Clojure for large programs*" thread. >> >> I took a look at Shantanu's macros, and I like the concept a lot. But I >> would prefer something baked into the :pre condition itself. The reason is >> that it just removes a layer of indirection. If you dig into ' >> *clj/clojure/core.clj*', you can see that the 'fn' macro is using >> 'assert' to test these conditions. Assert allows error messages to be >> applied, ie: >> >> *user => (assert false) * >> >> *user => (assert false "fubar") * >> >> >> >> However, (defmacro fn ...) assumes that just the boolean condition is >> being passed in, A). But I'd like to have the option to pass in a message >> B). >> >> >> *A) * >> >> *(def fubar * >> >> * (fn []* >> >> * {:pre [ (true? false) ] }* >> >> * (println "Hello World")))* >> >> *(fubar)* >> >> >> *B) * >> >> *(def thing * >> >> * (fn []* >> >> * {:pre [ [(true? false) "A false message"] ] }* >> >> * (println "Hello World")))* >> >> *(thing)* >> >> >> >> I reworked the 'fn' macro, only for the :pre condition, as a >> demonstration (see here <http://pastebin.com/fETV1ejJ>). The calling >> semantics don't change that much. Is there any interest in putting this >> into core? I'd use Shantanu's workaround otherwise, or in the interim. >> >> Thanks >> >> Tim Washington >> twas...@gmail.com >> 416.843.9060 >> >> >> >> On Sun, Jul 3, 2011 at 11:42 AM, Shantanu Kumar <kumar.s...@gmail.com> >> wrote: >> >>> >>> >>> On Jul 3, 7:39 pm, Timothy Washington <twash...@gmail.com> wrote: >>> > I'm using pre / post assertions quite a bit in a project I'm building. >>> And I >>> > too would love to see better or custom error messages for each >>> assertion. >>> >>> That should be possible with a macro. For example, I use this: >>> >>> https://bitbucket.org/kumarshantanu/clj-miscutil/src/acfb97c662d9/src/main/clj/org/bituf/clj_miscutil.clj#cl-1009 >>> >>> Maybe you need something like this(?): >>> >>> (defmacro verify-my-arg >>> "Like assert, except for the following differences: >>> 1. does not check for *assert* flag >>> 2. throws IllegalArgumentException" >>> [err-msg arg] >>> `(if ~arg true >>> (throw (IllegalArgumentException. ~err-msg)))) >>> >>> Then use it thus: >>> >>> (defn foo [m] >>> {:pre [(verify-my-arg "m must be a map" (map? m))]} >>> (println m)) >>> >>> Regards, >>> Shantanu >>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To post to this group, send email to clo...@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+u...@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 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.