On 1/8/2017 11:13 AM, Stephan Herrmann wrote:
I'm also surprised that some requirements are indeed specified with
regard to compilation units. Modules export packages, and types are
declared in packages. Isn't it possible to define requirements due to
JPMS solely in those terms (modules, packages, types), and avoid to
mention compilation units in these rules? What do compilation units add
conceptually to JPMS (besides adding complexity)?
Per 7.3: "The ordinary compilation units that are visible to M drive
the packages that are visible to M (§7.4.3), which in turn
drives the top level packages in scope for code in compilation units
associated with M (§6.3)."
Mentioning of top level packages here and in related locations makes
me wonder, whether package nesting (sub packages) is becoming
semantically relevant? I'm even under the impression, that
unnecessarily (?) defining a relation between packages and their
sub-packages leads to the unfortunate hand-waving in 7.4.3 to
discriminate "'really' observable" from "'technically' observable".
Am I missing any of the intended semantics if I consider all packages
as unrelated to each other, no matter whether or not the qualified
name of one package is the prefix of the qualified name of another?
The traditional semantics of subpackages meant that if package P.Q.R was
observable (due, say, to an observable compilation unit that declares
package P.Q.R), then packages P.Q and P had to be observable too. A
compiler processing compilation units in package P.Q.R couldn't turn
around and claim to know nothing about package P.Q or P. This enforces
the sense of packages forming a hierarchy, because arbitrary "levels"
can't be cut out -- a compiler can't claim to know about P.Q.R and P but
not P.Q.
I accept that the visible-to-module relation in 7.4.3 essentially
mandates a compiler to accept package hierarchies with missing levels,
because module exports are exact about packages and care not about
subpackages. P.Q.R could be visible to one module and P could be visible
to another module, and P.Q is not visible to any module at all.
In addition, the only rule that relied on observability of a package was
where 6.3 used it to put the simple name of a top level package in scope
(6.5.3 relied on this) -- but that explicitly needed a declaration of
package P, not just a declaration of a subpackage. Now that 6.3 and
6.5.3 rely on the visible-to-module relation, there is no need for
packages to be "technically" observable in the old sense, and you can
consider all packages as unrelated to each other.
As I already mentioned overloading, here's my example of the day:
...
Let me use the example to try validate my understanding of the concepts
involved:
Module Test reads module Base, so when compiling module Test all mentioned
compilation units are observable and visible.
Yes. I don't know what compilation units you mentioned explicitly on the
command line, but I'll assume that all interesting compilation units are
observable. Because Test reads Base, every package in Base is visible to
every compilation unit in Test. I specified it that way as setup for
later rules (TBD) that reason about insensible module graphs, e.g.,
where a package P in module M and a package P in module N are both
visible to the same compilation unit (not allowed at run time).
It's just that Base/other.Other is not accessible from any code in
module Test, right?
Right.
I read JLS as associating the *compilation units* with their respective
module.
But then two different compilation units declare types of the same
qualified name, which is an illegal name clash. What am I missing?
It's true that 7.3 also says that all the compilation units of Base
are visible to Other, since Other reads Base. javac is
effectively hiding Base's other.Other type from code in Other, since
Other already has an other.Other type. It's possible we need to
specify this explicitly.
Well, if you don't specify this, it's not part of the language, right?
I'm curious where in the spec this will be integrated.
4.3.4 would be the place to associate types with modules.
Will JLS9 enhance the concept of qualified names for types to include
the module?
No.
If Other/other.Other is visible to module Test it seems we need yet
another term for disambiguation between same-named types from different modules.
OTOH, visibility of this type seems to be crucial for overload resolution
if there's a sub class of Base/other.Other that is accessible from Test.
But: do you *want* Test to be able to invoke Base.test(Other) despite not
having access to the parameter type??
Yes, Test should be able to invoke Base::test(Other) even when Other is
not accessible to Test, just like the analogous situation today where
Other is package-access and the caller is in a different package but
passing an argument whose type extends Other. There is still no
conversion between Test's Other type and Base's Other type, so a
compiler should still consider Base::test(Other) as inapplicable for
Test's invocation.
Lastly, with the interplay of things defined in JLS vs. observability
which is subject to the host system, I wonder if JLS will at least include
"recommendations" regarding the structure of directories and compilation
units. The same holds for "association of a compilation unit to a module".
Otherwise, I'm afraid that different compilers will not be able to compile
projects developed with another compiler simply due to incompatible
directory layouts. Cf. the notion "the filename of the compilation unit is
typically module-info.java", which is still *very* weak, but *much* better
than nothing!
Noted.
Alex