Fork me on GitHub
#clojure-dev
<
2017-11-08
>
slipset09:11:19

Playing around with error messages, I’ve done something which produces this:

slipset09:11:48

user=> (defn foo ([x]) ([x y]))
#'user/foo
user=> (foo)
ArityException Wrong number of args (0) passed to: user/foo, expected arities: [1, 2]  clojure.lang.AFn.throwArity (AFn.java:435)
user=> (defn foo [x])
#'user/foo
user=> (foo)
ArityException Wrong number of args (0) passed to: user/foo, expected arities: [1]  clojure.lang.AFn.throwArity (AFn.java:435)
user=> (defn foo [])
#'user/foo
user=> (foo 1)
ArityException Wrong number of args (1) passed to: user/foo, expected arities: [0]  clojure.lang.AFn.throwArity (AFn.java:435)
user=>

slipset09:11:30

ie, it informs the user of what arities are expected. Would a ticket/patch for this be interesting?

slipset09:11:02

It mainly involves a couple of lines of code in Afn/throwArity

Alex Miller (Clojure team)13:11:58

How does it handle variadic?

slipset13:11:04

almost perfectly 😞

slipset13:11:31

public Object throwArity(int n){
    Class cls = getClass();
    String arities;
    try {
	java.lang.reflect.Method reqArity = cls.getDeclaredMethod("getRequiredArity");
	arities = "[" + reqArity.invoke(this) + "...n]";
    } catch (Exception e) {
	java.util.Set as = new java.util.HashSet();
	java.lang.reflect.Method[] methods = cls.getDeclaredMethods();
	for (int i = 0; i < methods.length; i++ ) {
	    as.add(new Integer(methods[i].getParameterCount()));
	}
	arities = as.toString();
    }
    String name = getClass().getSimpleName();
    throw new ArityException(n, arities, Compiler.demunge(name));
}

slipset13:11:30

This is the case that I don’t handle:

slipset13:11:33

user=> (defn foo ([x y]) ([x y z & rst]))
#'user/foo
user=> (foo)
ArityException Wrong number of args (0) passed to: user/foo, expected arities: [3...n]  clojure.lang.AFn.throwArity (AFn.java:442)
user=>

slipset13:11:57

Since it’s variadic and whatever-it’s-called.

slipset13:11:04

If I were to implement this all on my own, I’d probably choose to add this info to the Function object when it’s being compiled/read/parsed, and then have a function in AFn which returns the available arities.

slipset13:11:29

Something like getAvabailableArities

bronsa13:11:33

there's a ticket proposing that IIRC

slipset13:11:50

But that might incur problems that I’m not aware of…

slipset13:11:07

Because I guess we have all this info at read/analyze time and that we sort of throw it away, and then I try to figure it out again when the exception is to be thrown.

bronsa13:11:14

yeah, having it would also fix stuff like https://dev.clojure.org/jira/browse/CLJ-1279

Alex Miller (Clojure team)13:11:57

I’m pretty sure it’s not an accident that the expected arities are not an observable part of the function interface

bronsa13:11:25

they could be internal data tho

bronsa13:11:17

private to AFn

Alex Miller (Clojure team)13:11:23

Usually (this use case aside) if you’re asking that question, you’re probably doing something you shouldn’t

slipset13:11:27

But we can (sort of, I guess) ask for the requiredArity for a variadic fn, since

new GeneratorAdapter(ACC_PUBLIC,
			                                            Method.getMethod("int getRequiredArity()"),
			                                            null,
			                                            null,
			                                            cv);

slipset13:11:33

makes it public, right?

slipset13:11:17

But since neither IFn nor AFn declares this, it’s still somewhat private. In its own public way.

slipset13:11:04

Anyways, I’d really like to see the accepted arities in the error message, since it has annoyed me quite a few times that it’s not part of it.

slipset13:11:45

And if I were to really wish for something, the line-number of the offending call site would be so much more useful than the fact that the exception is thrown in AFn.java round line 440something.

bronsa13:11:43

you get that in the stacktrace tho

slipset13:11:23

at least not in the repl.

slipset13:11:39

but that might just be the repl catching.

slipset13:11:03

juxt:clojure erik$ java -cp target/clojure-1.8.0.jar clojure.main
Clojure 1.8.0
user=> (defn foo [x])
#'user/foo
user=> (foo)
ArityException Wrong number of args (0) passed to: user/foo, expected arities: [1]  clojure.lang.AFn.throwArity (AFn.java:442)
user=>

bronsa13:11:11

that's not the stacktrace

slipset13:11:49

Thanks! I’ve basically never used (pst)