On 4/27/2017 12:38 PM, Stephan Herrmann wrote:
On 25.04.2017 19:02, Alex Buckley wrote:
JPMS semantics (notably, dependency resolution) are defined by the API
specification (not the implementation) of
java.lang.module.Configuration and friends. JLS references to JPMS are
references to this Java SE API.

Got it. Since now JLS is no longer self-contained it would tremendously
help if we could get a list of which parts of the API specification are
expected to be considered at compile time. I understand that we need to
apply the naming rules for automatic modules. Is there more that should
be respected / validated / enforced at compile time?

The JLS was never self-contained as it always referenced a variety of java.lang and java.io types (and more recently java.lang.annotation and java.lang.invoke types). I have changed 7.3 to state:

"The host system must use the Java Platform Module System (as if by execution of the 'resolve' method of java.lang.module.Configuration) to determine which modules are read by M (§7.7.1). It is a compile-time error if the Java Platform Module System is unable to determine which modules are read by M."

That is, if a compiler processes a module declaration mentioning "requires X;", and the "as if" JPMS resolution fails because no module called "X" is found (whether an explicitly declared module with that name, or an implicitly declared i.e. automatic module with that name), then compilation fails too. The mapping from a JAR filename to an implicitly declared i.e. automatic module name is part of JPMS resolution. And even if a module called "X" is found, there are other reasons why JPMS resolution (and hence compilation) can fail, e.g. the module requiring X also requires Y and both X and Y export the same package. The JLS, as is traditional, allows a compiler to be as helpful or as terse as it likes w.r.t. the content of the compile-time error message.

Let me add a friendly reminder, that we are still waiting for a
specification that unambiguously tells us which module system to implement.
For illustration:

(A) Is JPMS a module system that keeps the semantics of qualified names as
they are in Java 8 and only superimposes encapsulation boundaries?
(i.e., each type is globally uniquely identified by its qualified name).

(B) Is JPMS a module system that maintains the assumption that from the
perspective of each module all relevant types can be distinguished using
their qualified name?
(i.e. admitting identical qualified names as long as no compilation of one
module will ever encounter several candidates at once).

(C) Is JPMS a module system that establishes a separate namespace for each
module, where types with identical qualified name - but defined in
different modules - need to be distinguished?
(i.e., uniqueness is primarily required for module-prefixed qualified
names).

Despite some efforts I fail to find a definite answer in JLS (and Alex
mentioned that some of this is still being discussed). Still JLS as of
today sounds mostly like (A). To me (B) sounds like the natural choice, but I
understood Alex as saying it *should* be (C). I don't see, however, how the
conceptual framework of JLS could possibly support such design.

(B) and (C) are not mutually exclusive because (B) was worded from the perspective of each module while (C) was not.

(B) is true. Assume two modules M and N each contain the type P.C, but neither module exports P (or, M exports P and N doesn't, or, N exports P and M doesn't). Then, a third module O can require M and N. If code in any module refers statically to a type P.C, then JPMS resolution guarantees that P.C is either defined by that module or is exported to the module by exactly one other module which the module reads.

At run time, when 'java' is run with M+N+O on the modulepath, the system will stop -- M+N+O will pass resolution (i.e. a Configuration will be constructed) but they can't all be mapped to the application class loader. javac will produce a lint warning to this effect. However, M and N and O are by no means "bad" modules, either individually or jointly, as M+N+O will work if mapped to a multi-loader layer. So, (C) is true too.

The JLS, as is traditional with classes and packages, does not restrict the modules which can be given as input for an invocation of a compiler. A compiler is assumed to be able to process multiple modules at once. In the case of M and N, a compiler will encounter P.C in M and P.C in N, and is expected to distinguish them -- code in M refers to P.C in M while code in N refers to P.C in N. This (C)-style property is now expressed in 4.3.4:

"Two reference types are the same compile-time type if they are declared in compilation units associated with the same module (§7.3), and they have the same binary name (§13.1), and their type arguments, if any, are the same, applying this definition recursively."

PS: I'm also having hard times to imagine, how those parts of the
specification, that are focused on compilation units, can possibly define
aspects like accessibility when looking at .class files, not compilation
units - but hopefully, this is just a technicality in how the spec is
worded, not a conceptual problem.

The JLS has never said how a compiler should process a mix of compilation units and .class files, yet compilers have figured it out. Everything in 7.3 about the host system associating compilation units with modules is applicable to associating class files with modules.

Alex

Reply via email to