On 4/20/2023 8:03 AM, Josiah Noel wrote:
We're talking about a case where module Y's primary purpose is not to implement SPI from X, but to provide its own packages/functionality unrelated to X. The classes in Y that use X should not be exported, and should only be loaded when X service-loadsĀ them. Hence, the Y module will use requires static to clearly inform that the classes are required at build time, but not for Y's normal operation.

We understand the scenario, which involves the module system allowing optionality not only of service providers for a given service, but also of the service itself.

However, as Alan has been saying, `requires static` doesn't have the precise, clear meaning that you think. When the module system sees the directive `requires static X;` in some module Z, the module system doesn't know the reason for the directive:

- Perhaps code in Z is annotated using annotation interfaces from X.
- Perhaps code in Z is going to reflect over the classes in X.
- Perhaps code in Z is implementing X's exported interfaces and the owner of Z is really sure that whenever Z is resolved, X is also resolved. (No use of ServiceLoader is intended in this item.)

You're going to say, "But that's Z, not Y! Y doesn't do any of those things! Y uses `requires static X;` to get a light touch on a service in X, and Y's service provision should be considered optional if X isn't available."

But Y and Z are the same to the module system -- each directs the module system to allow itself to be resolved even if X is not resolved. The module system then sees that Y wants to provide a service, but the module system has no idea where the service is, so fails fast at startup. This is a feature, not a bug. The classpath behavior, of only discovering that a service provider can't provide a service during run time (because the service is missing), is not what we wanted for modular services. If `provides` directives were treated as optional, i.e., ignored when the service can't be found at startup, people would say "Why bother with `provides`? It's no more reliable than putting everything on the classpath, when ServiceLoader throws because it can't instantiate the service provider."

So, I hope you can see why we are extremely cautious about acceding to requests to relax the checking of `provides`. In your scenario, Y is pulling double duty, which makes it harder to understand overall, and you'll benefit a lot more from breaking it up than from a more relaxed module system.

Alex

Reply via email to