About modules

Modules, ah, modules. The albatross of Java. I frequently joke that modules are scheduled for Java N+1 where N moves forward with each release. I remember perfectly the first time I heard of Java getting modules at Devoxx, back when they were still planned for Java 7. I remember I heard the announcement and what I saw made a lot of sense, I couldn’t wait to get them. I agreed completely, and still do, with the assertion that modules belong in the language, just like packages, and that they should not be delegated to third-party external systems which will never be able to have the level of integration that you can achieve by being an integral part of the language. And then, they pushed it to Java 8. And then to Java 9. It’s a shame because it looks like a really well thought-out module system.
Meanwhile, Ceylon already supports modules, in a generally awesome way. But why do we need modules? Here are some easy answers:

So why is it better if we have modules in the language, rather than outside of it?

These are the reasons why I can’t wait for Java N+1 to have modules, I think they’ll be great. But if you need modules now, then you can use Ceylon.

Ceylon support modules in the language, from the start, with:

Other existing third-party module systems

As I mentioned, we support using Maven repositories from Ceylon, and we will probably support OSGi too, in time. Those are the two main third-party module systems for Java. OSGi is used a lot in application servers or IDEs, but rarely by most Java programmers, which prefer Maven. Maven was the first system that provided both modularity and a build system for the JVM. Prior to that we had Ant, which only provided the build system. Maven essentially prevailed over Ant because it supported modularity, which meant that people no longer had to worry about how to get their dependencies. Even applying the modularity solution to itself, it became easier to distribute Maven modules than Ant modules.

Maven supports modularity and dependencies, in order to resolve and download them, but once they are downloaded, the dependencies are crammed into the classpath, so as far as the Java compiler or runner are concerned, modularity has been erased. There is no support for multiple versions of the same module at runtime, or any kind of validation of dependencies.

The undeclared transitive dependency problem

We recently had bug reports for Ceylon where our users has trouble using Maven modules from Ceylon, due to missing dependencies. Since we do use the dependencies provided by Maven, we found that a bit weird. After checking, it appears that we’ve been hit by the modularity erasure of Maven. Here’s a simple example of something you can do with Maven modules:

In Ceylon, if you tried to compile module A, the compiler would not let you because you failed to depend on C. With Maven, it just works, because Maven fetches modules B and C and puts them in the classpath, which means all implicit transitive dependencies end up visible to your module. Modularity is erased. This may seem convenient, but it really means that dependencies are not checked and cannot be trusted.

Due to that, we can’t rely on Maven modules to properly declare their dependencies, so we cannot run Maven modules in isolation.

The undeclared implicit dependency problem

There’s something more subtly wrong with unchecked module systems: implicit dependencies. This is something you’re allowed to do with Maven:

This is a variant of the first kind of problem, except that in this case nobody can use module B without also importing module C directly, because it’s not possible to use the types of module B without seeing the types of modules C.

In Ceylon, if you tried to compile module B, the compiler would not let you unless you export your module C dependency. This way, when you depend on module B, you automatically also depend on module C, because you really need both to be visible to be able to use module B’s API.

Another point in favour of integrated module systems

If we had an integrated module system from the start, in Java, with proper module isolation, we would not have the issues I just described with missing dependencies that are so widespread in Maven, because there are no tools to prevent you from making these mistakes. Compilers do not let you use packages unless you import them, there’s no reason to expect that the same would not hold for modules.

I still think the modules project for Java will be a great leap forward, but since Java N+1 is still not here, and there’s a huge library of Maven modules that we want to be able to use, we have to find a way to bypass the limitations of Maven’s dependency declarations to let you use them in Ceylon. We have various ideas of how to do that, from automatic detection of dependencies through bytecode analysis, to storing Maven modules in a “flat classpath” container, or even via dependency overrides where users could “fix” Maven dependencies. We’re still in the process of evaluating each of these solutions, but if you have other suggestions, feel free to pitch in.

Reference: About modules from our JCG partner Stef Epardaud at the Ceylon Team blog blog.
Exit mobile version