Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Errors by
edited by

(.a ""), rightfully, throws an IllegalArgumentException without a :phase.

One can consider, however, that this IllegalArgumentException is "compiler-like", while it doesn't seem primarily distinguishable of other IllegalArgumentExceptions that may be thrown in more "runtime-like" situations.

My problem is that, as a tool maker, without such a distinction, all IllegalArgumentExceptions will be given the same treatment, while users would want a more concise treatment (e.g. no stacktraces shown) for compiler-like ones.

  • Is there a recommended way to inspect runtime exceptions for determining if they represent something that, from the user point of view, represents "code that is invalid to begin with"?
    • (this is an informal term to describe runtime exceptions that are compiler-like)
  • Has it been considered to make this easier by e.g. attaching a :cause (or :phase, :ex-data, something) when the Clojure compiler/runtime can reliably do so?

2 Answers

0 votes

I would not consider this to be "code that is invalid to begin with" or compiler-like. It is syntactically valid code. When the member is not recognized it falls back to a reflective call which may fail at runtime. So, you could consider it a "Clojure runtime exception" or something, but we do not have any consistent thing that happens in that case, and there are probably 100s of places like this.

Runtime exceptions are generally not wrapped because we want to flow what was thrown. Throwing some kind of consistent exception from within the Clojure runtime that carried additional info might be useful, but I don't know that that is feasible to change at this point.

> When the member is not recognized it falls back to a reflective call which may fail at runtime.

What about when the type of the object is known at compile time? `(.a "")` feels "compiler-like" to me because we know up front the members on `java.lang.String` and `.a.` isn't one of them. It makes sense to fall back to the reflective call when it's `(.a someObj)`, but in the case of known types, what's gained by falling back on the reflective call?
0 votes
reshown by

This has been provided with the new Uniform qualified method syntax in Clojure 1.12.0-alpha6.

Instead of using (.a ""), use the Class/member syntax. In this case, (String/a ""). This will either compile (indicating that the Clojure compiler found a single method that matches the provided inputs), or it will throw a syntax exception (indicating that it found either 0 matching methods or multiple matching methods).

By only using this syntax, you can be sure that you're always matching against specific methods with no reflection.