Proposal: #CompileTimeDependences: `requires static`
Tim Ellison
Tim_Ellison at uk.ibm.com
Wed Jun 29 09:30:28 UTC 2016
mark.reinhold at oracle.com (Mark Reinhold) wrote on 28/06/2016 22:17:15:
> Issue summary
> -------------
>
> #CompileTimeDependences --- Provide a means to specify a module
> dependence that is mandatory at compile time but optional at run time,
> for use with libraries that are not strictly necessary but can be
> leveraged if present at run time. (Detail: If a dependence is
> "optional at run time" then does the module system try to satisfy it
> during resolution but fail silently if it cannot, or does it ignore it
> during resolution but add the corresponding read edge to that module
if
> it was resolved for some other reason?) [1]
>
> Use cases for this feature include annotations that need not be present
> at run time [2] and "auto-configuring" libraries and frameworks such as
> Joda Beans [3] and Spring [4].
For some reason I can't quite explain, this feels like we are giving up
on one of the fundamental completeness assurances of a coherent modular
application. Is this a new failure mode for link/run time modular systems
that has not previously existed?
It may be that this proposal satisfies an important compatibility story
for
existing code bases, and that is the justification, because on first
reading
my reaction is that the code has to be written to deal with the absence of
the optional module anyway, more details below.
> Proposal
> --------
>
> Extend the language of module declarations to allow the `static`
modifier
> to be used on a `requires` directive, with the following meanings:
>
> - At compile time, `requires static M` expresses a mandatory
> dependence. It is an error if a suitable module cannot be found
> amongst the observable modules and resolved.
>
> - In phases after compile time, `requires static M` expresses an
> optional dependence. The module system will not search the
> observable modules for a suitable module during resolution, but
> if the resulting module graph contains a suitable module then it
> will add the appropriate readability edge prior to doing the usual
> post-resolution sanity checks. (The parenthetical question in the
> issue summary is, in other words, answered in the negative.)
I read the parenthetical question as an either-or ...
> Thus a hypothetical module declaration of the form
>
> module joda.beans {
> requires static joda.collect;
> ...
> }
>
> would ensure that the `joda.collect` module is available at compile
time,
> so that code in the `joda.beans` module that refers to `joda.collect`
can
> be compiled without any fuss. It would not, however, guarantee that
> `joda.collect` is available at link time or run time. A user who wants
> to use `joda.beans` together with `joda.collect` in those later phases
> must ensure that `joda.collect` is added to the module graph by, e.g.,
> declaring a dependence upon it in some other module, or by using the
> `-addmods` option or its equivalent.
>
> The code in `joda.beans` that refers to types in `joda.collect` must, of
> course, be written defensively so that it fails gracefully at run time
> when the `joda.collect` module is not present.
This is a key point. Since the application code has to be robust in the
face
of a missing "requires static" module, wouldn't it be better served by
coding
the behvior of the required module as a service that has a "fail
gracefully"
implementation and can be replaced by a productive implementation if
required
at link/run time?
I guess a weak analogy would be using compile against JARs that have no
runtime
equivalent, and are used to produce code that can fail at runtime, vs.
having
a type of service or strategy pattern that encompasses the fail gracefully
/
be productive implementations.
> It is possible to combine the `public` and `static` modifiers on a
> `requires` directive:
>
> module joda.beans {
> requires static joda.collect;
> requires public static freemarker;
> ...
> }
>
> This is useful in this particular case since `joda.beans` defines two
> exported public classes that extend classes defined in the `freemarker`
> module, and so those classes are logically part of the `joda.beans` API.
> In general, however, this idiom leads to fragile APIs and is therefore
> not advised except when dealing with legacy code.
>
> Notes
> -----
>
> - In phases after compile time, why doesn't the module system search
> the observable modules in an attempt to satisfy an optional
> dependence?
>
> This would not be difficult to arrange but it could lead to surprising
> behavior in which optional dependences silently cause many additional
> modules to be resolved. Given the use cases we have it does not seem
> unreasonable to expect an end user to indicate explicitly, either in
> source code or out-of-band (e.g., with a command-line option such as
> `-addmods`), that an otherwise-optional module is actually needed.
Another option would be to provide a command-line option that explicitly
allows
the linker/launcher to ignore missing modules that are required where
there is
an assurance that it will not actually be required in the particular
context;
that is, if I design a single module with "requires" or "requires static"
dependencies if it is used in a stand-alone or container context, for
example.
I'd prefer to fail because of an explicit -ignoremods option on the
command
line rather than a missing -addmods.
Regards,
Tim
> [1] http://openjdk.java.net/projects/jigsaw/spec/issues/
> #CompileTimeDependences
> [2]
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-October/004915.html
> [3] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/
> 005462.html
> [4] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/
> 005814.html
>
Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number
741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6 3AU
More information about the jpms-spec-observers
mailing list