15 January 2019
By: Tomas Malmsten

Encapsulation in Java and Kotlin

Over the past week I've been looking at how I can create a well encapsulated library SDK for Android. What I am looking for is the ability to hide all implementation details from the client whilst still have the freedom to design the SDK code base well.

It has been an interesting deep dive into Kotlin, with a focus on how to encapsulate members in the language. I must say that I'm more and more impressed with the language design the more I understand it.

Here I'll try to explain the way the viability modifiers work, both in Kotlin and in Java, and why Kotlin has done it a lot better then Java. I'll also touch on the differences between Java on Android and Java on the server, especially with regards to Java 9's Java Platform Module System (JPMS).

In Java we are rather limited when it comes to visibility modifiers as there is no concept of a module (until Java 9). If we want to create a module (like a library or SDK) and have several packages within this module there are no means to hide the internals from the client.

Java has the following modifiers:

  • public - visible to everything.
  • protected - visible to the inheritance chain, I.E. child classes.
  • package private (default) - visible to all members inside the current package.
  • private - visible to anything inside the class (which is synonymous to inside the file in Java).

This means that the only way we can ensure that nothing is visible outside the module is to make everything either package private or private. We can't use public or protected since this will expose the members to the client. For a reasonable complex SDK this means we will struggle to keep things hidden as well as be able to use package structures as a way to organise our code.

In Kotlin we have the following modifiers:

  • public (default) - visible to everything.
  • protected - visible to the inheritance chain.
  • internal - visible to everything withing the module.
  • private - visible to anything within the file, including other classes and functions in the file (for top level modifiers).

This gives us a lot more to work with. Lets start with defining what a module is in Kotlin. A module is defined as a compilation unit, I.E. a collection of things, in packages, that are compiled together. In Java terms this loosely corresponds to a JAR file.

The key here is the internal modifier. It allows us to ensure that anything that is marked internal stays internal to the module, not just to the package. Which means that we can create a SDK with many packages without exposing implementation.

This makes Kotlin a much better language for developing libraries and SDKs. Especially for Android, as there are no alternatives if you want to create this kind of well encapsulated libraries. But you have to make sure not to forget the internal modifier. Configure your IDE to default to private, then you will have to think about opening things up. Which you should, regardless of what you code.

There are a couple of things that I would have liked to see in Kotlin, to improve it even further:

  • Anything marked as protected will be exposed to the client as well. I would have liked to be able to mark members as internal protected. This would make it possible to design the module with both internal and external extendability.
  • I miss the package private modifier. I use this a lot as it makes writing modular implementation that is easy to test much easier. I would have liked it on Kotlin as well.
  • As mentioned to above I would also like to make it harder to make things public. I like the way Java designed this. Making package private the default and forcing the developer to think an extra time when making anything public. I'd even go a step further and make private the default. It should require thought to open your code up.

With the release of Java 9 and the Java Platform Module System there is now a first class concept of modules in Java. If you use JPMS you can now clearly declare which classes or packages you want the outside world to see. Due to compatibility issues it is possible to switch this of, but if you develop for pure Java 9< JPMS is really powerful. For more information on how it works you should read this InfoQ article. It explains how to create a module and also how to utilise Java's built in service loader to expose services from the module. This is also possible if you use OSGi which is another module system for Java, with a lot of extra futures. It is good at what it does, but probably overkill for many applications, and perhaps not the best solution for a general library.

Tags: Kotlin Architecture Java