Refactorability proposal...

Stanley M. Ho Stanley.Ho at
Thu Jun 12 11:02:08 PDT 2008

Hi Bryan,

I agreed that refactorability is indeed an important issue we need to 
address. That said, there are couple concerns I have related to step 1b. 
I'm not arguing against import-by-package at runtime; only against the 
transformation of import-by-module to import-by-package at compile-time.

A compile/build-time transformation from import-by-module to 
import-by-package could fundamentally be done in one of two ways.

First, it could involve analysis of the module's method signatures. The 
issue is that the analysis may not be accurate all the time (e.g. code 
that uses reflection, Class.forName(), etc.). The programmer will then 
be required do extra trial-and-error steps to fix up the dependencies in 
the metadata, and this is not acceptable.

Second, it could simply expand import-by-module as the set of exported 
packages in the imported module, then there is a problem when migrating 
from one version of an imported module to a newer one and the set of 
packages have changed. Suppose a core module in JDK 7 exports package P 
and the one in JDK 8 exports packages P and Q. If a module imports JDK 
7+ and is compiled against JDK 7, step 1b will transform the module to 
import only the packages that are known in the core module in JDK 7. 
When this module runs in JDK 8 or later, it will not see the new 
packages. This is problematic because many modules will compile against 
an older version of the JDK and want to call new API in newer JDK 
through reflection; in general, this situation applies to using other 
libraries as well. This will also cause problem in applications that 
involve weaving at runtime and the exact required packages are not known 
at compile-time.

There are some general problems with expanding modules to packages at 
compile/build-time, regardless of how the expansion is achieved.

First, there are modules (e.g. classpath module) that cannot logically 
have exported packages which are known at compile-time and at runtime, 
thus it would be impossible to perform the transformation in this case. 
(Technically, we can go through every JAR in the classpath in every 
launch to find out the exports of the classpath module at runtime, but 
this has huge startup performance impact.)

Second, it implies that people export packages but import modules. This 
will be hard to explain to beginners.

Last, but perhaps the most important, it means that unresolveable 
packages at runtime will generate error messages which the programmer 
must manually map back to imported modules and the transformation 
process implemented by a tool. The fundamental aim of a programming 
system should be to reduce the semantic gap between what a programmer 
sees in code and what a programmer sees at execution; the mapping from 
packages back to modules increases the semantic gap.

I accept that pushing module imports through to runtime makes it hard to 
"rewrite" a program (i.e. to refactor module members) but it makes it 
easy to "read" the program (in the sense of a small semantic gap between 
what imports are read/written and what imports are executed). A core 
Java principle has always been that reading is more important than 
writing, so we do not believe increased ease of refactoring on 
relatively rare occasions is worth complicating every single reading of 
a dependency.

I still think the refactorability problem you brought up is very 
important to address. That said, the proposed transformation seems to 
have many issues as an acceptable general solution.

- Stanley

More information about the jsr277-eg-observer mailing list