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)
That should be possible with a macro. For example, I use this:
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.
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
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). 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
--
I do think a simple String error message is all that the user of the function should provide. From there, An AssertionError can throw up something along the lines of what you said - Expected… , Found… , Message. That would give enough information for reporting at least in a test framework. To get more precise information, like you said, that AssertionError could also throw up class/file information, etc. that a debugger could use. I would guard against designing these things to accomodate a context outside of it's execution scope. In the ideal functional world, the input and output are wholly localized. Any Error/Exception thrown can be consumed or chained to give very precise failure reasoning.
As for how that would fit into the entire exception chain, that's still being thought (see here). There are already a few approaches, and I think this (see here) is the context of how the core team is approaching this problem.
Cheers
(require '[clojure.test :refer [is]])=> nil(defn get-key [m k] {:pre [(is (map? m) "m is not a map!")]} (m k))=> #'user/get-key(get-key [] 0)
FAIL in clojure.lang.PersistentList$EmptyList@1 (form-init8401797809408331100.clj:2)m is not a map!expected: (map? m) actual: (not (map? []))AssertionError Assert failed: (is (map? m) "m is not a map!") user/get-key (form-init8401797809408331100.clj:1)
(defn somefn [x]
{:pre [(or (map? x) (throw+ {:type ::bad-stuff :details ...}))]}
...)
(defn get-highlander [hs]
{:pre [^{:msg "There can be only one"} (= 1 (count ^:var hs))]}(first hs))
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)
(assert (test (complex (form (with (a ^:var varible))))) "bad variable")
(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))))))))