The baby and the bathwater

Stephen Colebourne's recent blog entry [1] contains many true statements, along with some reasonable advice for library maintainers. To summarize: - As of Java 9, with Jigsaw, there are two ways in which a library can be used: Either on the traditional class path, or on the newfangled module path. If you maintain a library but don't modularize it then it can still -- unbeknownst to you -- be used on the module path as an automatic module. - When code runs on the module path there are some differences in the behavior of some pre-9 APIs, in particular those related to resource lookup. - As a consequence, if you maintain a library that's intended to work on Java 9 or later then you should test it on both the class path and the module path, even if you do nothing to convert your library to a module. If your library doesn't work on the module path then you should either fix it or document that limitation. - If you don't modularize your library, or at least claim an automatic module name for it via the `Automatic-Module-Name` manifest entry, then you potentially block the maintainers of libraries that depend upon yours from modularizing their own libraries. - The tools that we use, and in particular Maven, could be improved. It's difficult to compile the classes for a modular JAR file that's intended to work on the class path of pre-9 releases, it's difficult to test a library on both the class path and the module path, and various Maven plugins still need to be upgraded to handle (or else ignore) `module-info.java` files. (Stephen has helpfully filed issues in the appropriate bug trackers for some of these problems.) - Some old tools, bytecode libraries, and other systems fail when they encounter `module-info.class` files or multi-release JAR files. From these points Stephen concludes that the module system, "as currently designed, has 'negative benefits' for open source libraries," saying that this is primarily because "the split (bifurcation) of the module-path from the class-path is an absolute nightmare." Hyperbole aside, Stephen's main complaint here is only about the need to test a library on both the class path and the module path if it's intended to work on Java 9 or later. With automated testing this shouldn't, in principle, be a huge burden, but still it's worth asking the question: Could we have avoided the need for such dual testing if we hadn't introduced the module path as separate from the class path? Consider, as a thought experiment, an alternative Jigsaw design that didn't have a separate module path, and instead treated modular JARs on the class path as modules rather than traditional JAR files. You wouldn't have to dual-test if your baseline is Java 9 or later, but if you want to support earlier releases with the same artifact then you'd still have to test on the class path. With the actual Jigsaw design you do need to dual-test your library when your baseline is Java 9 or later. There is, however, a benefit to this: If someone uses your library in an application that works on the Java 8 class path today then they can migrate it to the Java 9 (or later) class path and then, when they're ready, move your library (and perhaps some others) over to the module path. (There were many other reasons to define the module path as separate from the class path, but those aren't directly relevant here.) The tradeoff, then, is a little bit more dual testing on the part of library maintainers in exchange for greater flexibility for those who will migrate existing applications to Java 9 or later releases. Many library maintainers will be reluctant to baseline to Java 9 (or later) for a while yet, so they'll be dual-testing anyway, so I think this was the right tradeoff. Stephen closes with a specific suggestion: "There needs to be a way for a library author to insist that the modular jar file they are producing can only be run on the module-path (with any attempt to use it on the class-path preventing application startup). This would eliminate the need for testing both class-path and module-path." Yes, this would eliminate the need for dual testing, but only if you're willing to baseline to Java 11. As with a unified class/module path, however, if you want your library to work on earlier releases then you'd also, still, have to test on the class path, and you'd make it harder for application maintainers to migrate old class-path applications. I don't think this idea is worth pursuing. What ideas are worth pursuing? We should, by all means, continue to improve our tools, Jigsaw itself, and the rest of the JDK. Several of us here collaborated on the initial support for modular development in Maven, but clearly there's more to do. If nothing else, the Surefire plugin should be able to test a library on both the class path and the module path. There's also at least one improvement in the JDK worth considering, which a few of us have already discussed, namely a small enhancement to javac that would allow a single invocation to compile a module, in module mode [2], but target class files other than `module-info.class` to an earlier release [3]. To sum up: We have more work to do, based on practical experience. This shouldn't be a surprise, with a change to the platform of this scope. Let's keep doing that work, let's not unduly alarm ourselves or anyone else, and please let's not throw out the baby with the bathwater. - Mark [1] http://blog.joda.org/2018/03/jpms-negative-benefits.html [2] http://openjdk.java.net/jeps/261#Compile-time [3] https://bugs.openjdk.java.net/browse/JDK-8200254