-
-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Wrong number of args" ArityExceptions are misleading #54
Comments
Failing test ( (m/defmulti mf5
{:arglists '([x y])}
(fn [x & _]
(keyword x)))
(m/defmethod mf5 :default
[x y]
{x y})
(m/defmethod mf5 :after :default
[x m]
(assoc m :after x))
(t/deftest arity-exception-test
(t/testing "'Wrong number of args' errors should not include `next-method` in the number of args passed (#54)"
(t/testing "Sanity check"
(t/is (= {:x 1, :after :x}
(mf5 :x 1))))
(t/is (thrown-with-msg?
clojure.lang.ArityException
#"Wrong number of args \(1\) passed to: methodical\.macros-test/mf5-primary-method-default"
(mf5 :x)))
(t/is (thrown-with-msg?
clojure.lang.ArityException
#"Wrong number of args \(1\) passed to: methodical\.macros-test/mf5-after-method-bad-after"
(mf5 ::bad-after 1))))) I poked around at fixing this a bit but I think what we need to is either:
|
Messages are also pretty bad if you add methods programmatically e.g. with |
Dispatch function arity errors aren't nice either =( (m/defmulti x
(fn [x y]
[(keyword x) (keyword y)]))
(m/defmethod x [:x :y]
[x y]
{:x x, :y y})
(x :a)
;; => Wrong number of args (1) passed to: methodical.impl.combo-test/eval34222/fn--34224 We could wrap the dispatch function in a |
I think the only reasonable way of implementing this would be to automatically wrap the primary method function in something that does a try-catch and catches If the choice is between better errors or slightly better performance, I think we should choose better errors |
Wrapping things doesn't actually have a dramatic effect. A third of a nanosecond on my computer |
Here's an example of how we might accomplish wrapping things (defn wrap-dispatch-fn [f ^String fn-description ^Integer num-implicit-args]
(letfn [(rethrow-arity-exception [^clojure.lang.ArityException e]
(throw (doto (clojure.lang.ArityException.
(- (.actual e) num-implicit-args)
fn-description
(.getCause e))
(.setStackTrace (.getStackTrace e)))))]
(fn
([]
(try
(f)
(catch clojure.lang.ArityException e
(rethrow-arity-exception e))))
([a]
(try
(f a)
(catch clojure.lang.ArityException e
(rethrow-arity-exception e))))
([a b]
(try
(f a b)
(catch clojure.lang.ArityException e
(rethrow-arity-exception e))))
([a b c]
(try
(f a b c)
(catch clojure.lang.ArityException e
(rethrow-arity-exception e))))
([a b c d]
(try
(f a b c d)
(catch clojure.lang.ArityException e
(rethrow-arity-exception e))))
([a b c d e]
(try
(f a b c d e)
(catch clojure.lang.ArityException e
(rethrow-arity-exception e))))
([a b c d e & more]
(try
(apply f a b c d e more)
(catch clojure.lang.ArityException e
(rethrow-arity-exception e)))))))
(ns-unmap *ns* 'x)
(m/defmulti x
(let [dispatch-fn (fn [x y]
[(keyword x) (keyword y)])]
(wrap-dispatch-fn dispatch-fn
(format "Methodical multimethod %s dispatch function %s"
(pr-str `x)
(some-> dispatch-fn class .getCanonicalName))
0)))
(m/defmethod x [:x :y]
[x y]
{:x x, :y y})
(x :a)
;; => Wrong number of args (1) passed to: Methodical multimethod methodical.impl.combo-test/x dispatch function methodical.impl.combo-test/eval36766/dispatch-fn--36768 |
If you call a
defmethod
with the wrong number of args you'll get a misleading arity exception that reports you've passed one more are than you actually have:This is of course because the
defmethod
actually macroexpands toand gets the extra
next-method
parameter...instead of macroexpanding to
we could do something like
so we get correct error messages. I don't think this would make a noticeable performance difference but probably worth benching just to be sure.
Alternatively just write reify a version of
IFn
that gives meaningful error messages. Maybe it could even include stuff like the dispatch valueThe text was updated successfully, but these errors were encountered: