Module descriptions versus module descriptors

David M. Lloyd david.lloyd at redhat.com
Thu Dec 10 15:02:38 UTC 2015


On 12/09/2015 07:26 PM, mark.reinhold at oracle.com wrote:
> 2015/10/20 4:27 -0700, david.lloyd at redhat.com:
>> I see no logical path that leads from the requirements as specified
>> exclusively to the assumption that the descriptor must be bytecode, let
>> alone part of the JVM and/or language specification. All the reasons
>> given appear to be self-justifying or based on abstract assumptions,
>> e.g. "modules are... a new kind of Java program component... therefore
>> [Jigsaw] treats them as such".
>
> I agree that there are other ways to represent module descriptions.
> I've never stated otherwise.
>
> If module boundaries, however they're expressed, are to be enforced by
> the compiler and the VM -- as you've agreed elsewhere -- then their
> manner of expression is inevitably going to be a topic for the Java
> language and VM specifications.  This is not avoidable.

Actually that does not logically follow.  I could, for example, 
"express" module boundaries in the VM by creating a hard equivalence 
between modules and class loaders, and in the compiler via command-line 
arguments.  In this way, no langauge or VM specifications must change; 
in fact only the specification of the compiler tool itself *must* 
change.  Granted it is *likely* that in such a case, one would go 
further and maybe make some small modifications to the javax.tools API 
as well to facilitate the provision of resources on a per-module basis.

>>            ... it seems to me that a significant part of the Jigsaw
>> design justification for its handling of module metadata hinges around
>> the conflation of the description of a module, and the descriptor used
>> by the static module loading implementation.  This raises a red flag for
>> me because it fundamentally locks the capabilities of module
>> descriptions to whatever makes sense to express in the descriptor, and
>> then in turn constrains these things to the language and JVM specification.
>>
>> In our (JBoss) module system, these concepts are decoupled: a filesystem
>> module's descriptor is read and parsed into a description which is then
>> consumed by the module system to create the module.  ...
>
> If module boundaries are to be enforced by the compiler and the VM then,
> in such a decoupled system, where and in what form does the compiler
> locate the information that describes the module being compiled, and any
> other modules required in order to compile that module?

You (or rather, the build tool) would tell it.

In real nontrivial systems, the universe of compiled and packaged (and 
versioned) artifacts is what you use when you're building another piece 
of the system.  The installed set of modules is necessarily a subset of 
this total universe.  Because of this, if I'm building something I 
generally cannot say "I have a build dependency upon 
org.apache.commons.collections".  I must say "Build against 
org.apache.commons.collections, version 3.2.2", and furthermore I might 
have to also specify whose build of such I use, and where to get it 
from.  And, I commonly must build different pieces of my universe 
against different versions of the same thing, especially when pieces 
come from a third party.  I will likely not use the same version I built 
against in the final system, especially in an evolving system, which I 
believe is a critical use case.  Finally, I may use the final built 
artifact in a variety of systems, whereupon it is necessary to modify 
the run time name and/or linkage information depending on the 
requirements of the target system.  I will almost certainly not even 
test the two together until a later integration testing phase, which (in 
probable addition to an ABI compatibility checking tool) will be the 
last stage before accepting the new module into the installed set.

In other words, it is often necessary to enforce different module 
boundaries depending on circumstances related to build, install, and 
run, independently of the rest of the source code.  Much of this 
information may not be available at all when the original artifact is 
being built.  Any bundling of module descriptor information inside of 
the module contents will have the effect of rendering that module 
useless in any module environment that is sufficiently unlike the one 
for/in which the module was built (unless you modify the module itself 
after the fact).  It is not realistic to assume that the version of a 
module that is compiled against is the version that will be run against, 
and it's misleading to "newbies" who might expect some kind of global 
cohesion between modules without any kind of limiting context (e.g. a 
module distribution, or a specific application).

The power that a modular Java gives you is that you can leverage what is 
arguably Java's best feature - the ability to easily provide perfect ABI 
stability between versions, and therefore the ability to substitute 
modules in the run-time environment - in order to maintain a growing and 
evolving ecosystems, or indeed many such ecosystems.  This is not unlike 
what many OS distributors can do, and for similar reasons in a similar 
way (though we have the sizable advantage of Java's more powerful 
linking capabilities at our disposal, which makes some hard things easy, 
and some impossible things possible).  I think that the module system 
should do what it can to enable this, and to me that means: external 
module descriptions, i.e. the compiled artifact (which consumes and/or 
provides specific ABI(s)) should be separate from the install/run 
linkage (which specifies how to tie modules together in such a way that 
all necessary ABI requirements are fulfilled).  This is because the 
artifact build dependency information is superficially similar to, but 
fundamentally not the same as, the run time linkage information - and 
this will be true no matter what we do or what constraints we place. 
The only thing we can influence in this regard is, how hard do we make 
these use cases to achieve?

There are other reasons that I prefer this approach as well, but this is 
the reason that directly answers your question.  And there are possibly 
other approaches that would also solve the same problems - for example, 
a hybrid approach where exported and non-exported packages are listed 
and annotated within the module, but the dependence information is 
external and provided separately at build time and run time (in a manner 
suitable to each situation).

-- 
- DML


More information about the jpms-spec-observers mailing list