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

+3 votes
in Clojure by

Copied from this reddit comment:

So if an ambiguous method is a syntax error (syntax, really?), does that mean that when I update a Java lib that provides a new overload, it will break my code? Even worse, if I have a Clojure lib on the classpath that uses a Java lib, and then update the Java lib and it now provides another overload, the Clojure lib breaks. This would be bad and could result in all kinds of update hell.

Adding an overload is a very common backwards compatible change in Java code that should be expected. Please don't make it create "syntax" errors in Clojure wrappers.

My own words:

One of Clojure's strengths is the resiliency of code, that something written years ago still works today. This has historically applied to libraries that provide idiomatic wrappers around Java libraries as well. However, the use of syntax errors instead of falling back to reflection means that such libraries (if they use the new method values syntax) will be more brittle than other interop code, limiting its usefulness in long-lived code.

I understand the reasons for using hard errors (performance, clarity, simplicity), but I agree that it's a strange choice given Clojure's otherwise incredible flexibility and willingness to support a variety of usages.

What is lost or degraded by falling back to reflection (and a reflection warning) in ambiguous cases?

3 Answers

+1 vote
selected by
Best answer

This has been discussed at length in threads elsewhere on reddit and slack, so I will be brief, but the intent here is to make a high quality method value (specific, explicit, no reflection, proper hints/coercions) and creating a reflective method value is generally not something we want to do. This intention is different than previous interop features, and should drive choices about what to use in the future (which I expect will evolve).

+2 votes

We appreciate the question here and it's given us some new ideas and we'll incorporate into the next iteration, thanks.

Oooh interesting. Thanks for the follow-up.
0 votes

One of Clojure's strengths is the resiliency of code, that something written years ago still works today.

And if you do not change the dependencies, it will continue to work.

I think folks need to consider why you would update a Java library that one of your existing dependencies depends on? If you leave it alone, it continues to work. It only breaks if you explicitly change the version in your own project and that sort of change always has a risk that you're going to break a dependency that also uses it.

Yes, there are sometimes good reasons to override the version of a Java library -- to address a CVE, for example -- or perhaps you have two dependencies that both rely on that Java library and you want to update one of those dependencies. But those sorts of changes always carry a risk -- and even patch release updates of Java libraries can (and do!) introduce breakage in all sorts of ways.

As someone who has a CI pipeline that will fail the build if a new reflection warning appears, I'd much rather have a guarantee of no reflection and to see that error immediately, locally, than not catch the problem introduced by the change further down the line.

And in case someone says "Well, actually... if you depend on A and B and they both depend on Java lib C and you update A and that uses a newer version of C, it could break B!" -- if you do not change the dependencies, it will continue to work.

If you update a library that changes your transitive dependency versions, you always have a risk of breakage.