Making Platform Interop even smoother

Being 100% interoperable with the JVM, and subsequently with JavaScript, has always been among Kotlin’s top priorities. With the amount of existing code, and a rich JVM ecosystem, having the ability of interoperating and leveraging these is crucial.

With the upcoming release of M9 we’ve improved on this, making the integration even more seamless.

Platform Types

Dealing with nulls is one of the biggest issues when it comes to Java  interoperability. Almost any Java method may, potentially, return null, so Kotlin has treated Java types as nullable, and we either need to resort to using the safe-call (?.) operator or notnull-assertion (!!) to avoid compilation errors:

on trying to pass the value x to the following functions:

in the first case, Kotlin compiler would issue an error. This means that the call to nullNotAllowed would need to be:

As of M9 this is no longer the case. This allows for much cleaner code, and avoiding the overuse of ?. and !! operators when interacting with Java.

Much the same way, when implementing Java interfaces, methods that can have potentially null arguments, no longer require these declarations to be declared as nullable in Kotlin. For instance, given:

when implementing this in Kotlin:

the parameter input no longer has to be of type String?. You can choose to make it either String or String? — depending on its actual meaning. In this example we chose input to be not-null, and data to be nullable.

Annotating methods with platformStatic

Kotlin has object declarations which can be viewed as singletons. And these are consumable from Java, albeit not with the nicest syntax. Given:

consuming this from Kotlin, would be:

whereas from Java it would look like this:

With the next release, we’ll be able to call the method from Java the same way as from Kotlin by simply adding an annotation to the function declaration:

making the code much cleaner. Same applies to class objects.

Removing roadblocks

Another benefit of platformStatic is removing some showstoppers that existed when using certain Java libraries such as JUnit. In particular, the latter requires a static method in Java when using Theories. The workaround for this was quite tedious. Fortunately, this is no longer the case. We can use the platformStatic annotation to solve this issue.

Leveraging overloaded functions with platformName

When having overloaded methods that use generics such as:

While calling these from Kotlin is possible, trying to invoke these from Java is problematic due to type erasure. Similar to platformStatic, we’ve introduced the platformName annotation that allows to rename the function so that when invoked from Java, the new given name is used:

This can now be called from Java as follows:

Note that this is not the only use case for platformName.

Private property accessors

Property accessors are no longer generated for private private properties in Kotlin, which means that conflicts with existing getXYZ methods do
not occur if unnecessarily. Take the following interface in Java:

If we are to implement this interface in Kotlin and our class has a private property named bar, in M8 and previous versions it causes a conflict, and we’d have to name the property to something different than bar. Starting with M9, this is no longer the case. As such, the code below is perfectly valid:

Summary

With these changes coming in M9 we’ve removed some roadblocks and more importantly aimed at making the interoperability between Java and Kotlin much cleaner. And while these improvements can make consuming existing Java code more pleasant, it also allows for an even better experience of writing new libraries and functionality in Kotlin and consuming these from Java.

As always, we’d love feedback. Let us know what you think.

Note: M9 has not been released yet, but you can find these features on the nightly builds

This entry was posted in Language design. Bookmark the permalink.

31 Responses to Making Platform Interop even smoother

  1. Anton says:

    So there is implicit invisible !! on values returned from Java code?

  2. Dmitry says:

    Hmm. I have read in Kotlin docs that one of the priorities of the language is to save a developer from NPE’s by making those areas of code explicit.

    Do you steer away from this now? Because it seems like the code can now silently start throwing NPEs just like in Java :) Of course this is only about interop code if I understood right, but still.

    • Hadi Hariri says:

      We’re not steering away, we’re just trying to get the experience a bit smoother and the code a lot more cleaner/readable. Reality of the matter is that if your code is exposed to nulls, you’re going to have to deal with them. Using !! and/or ? isn’t going to magically save you.

  3. Dan says:

    While annoying at first, the ?. and !! operators are very descriptive of areas where nullable types show up. I use them myself to limit how far I let nullables into my API from the ‘lax’ Java world. It’s nice to ‘lean’ on the Kotlin compiler to show me the mistakes I’m allowing in my code. Also, this seems inconsistent and hard to explain to those who are new to Kotlin; I think a strict set of rules defining nullables shouldn’t be eschewed in return for a having to type a few less characters.

    • Hadi Hariri says:

      You can still do that. If you’re consuming a Java method and assigning the result to a variable, you can be explicit about the declaration and if you declare it as nullable, then you’ll still get the compiler error.

      • Dan says:

        Yes, I can choose to be explicit, and I do see the introspections of Any! etc from Java. I still think this is inconsistent.

        For people learning the language, the rules and reason for nullable types are less clear if the rules only apply in some cases.

  4. soren says:

    I recently read this Alex Payne blog post in which he has a negative opinion about the future of “compile to javascript” languages. He thinks it complicates the toolchain and actually adds cognitive overhead. I for the most part agree.

    https://al3x.net/2014/09/16/thoughts-on-five-years-of-emerging-languages.html

    While I think it’s worth keeping a javascript backend as a future possibility I think it would be prudent to put it on the back burner(i.e. stop advertising/touting/distributing it) until the fallout of the transition to es6 is done. I just don’t see the value anymore of kotlin over typescript, traceur, and other dedicated transpilers and I don’t see the value of any transpiler over regular javascript in the long run. Just as the need for an llvm backend has dissipated with the robovm, there will likely be good java bytecode to javascript translators when asm.js can start handling vm langauges. I also think managing the transition to targetting es5 vs es6 will be a pain in the arse considering things like moduling and library bindings. I also think a javascript backend will be a distraction to the kotlin community in the future.

    Again IMO, a kotlin javascript backend should wait until it’s possible to target asm.js and maybe even scrapped if generic jvm bytecode to asm.js translators become good enough.

    • soren says:

      One possibility I left out for those wanting kotlin flavored javascript is that the projects should be made separate… let there be a kotlin and a kotscript and let them evolve separately but mindful of each other and their underlying platforms.

    • David Leppik says:

      Just because you don’t have a use case for compiling to JavaScript doesn’t mean it isn’t really useful. There are a number of platforms (iOS, web browsers) where JVM isn’t an option. What’s more, legible JavaScript is valuable for debugging, and for interoperability with JavaScript libraries. GWT and Dart went the impenetrable compiled JavaScript route, and it isn’t helpful.

      I develop in Scala (server-side) and TypeScript (client-side). I would have gone with Kotlin, if its JavaScript support had been more mature when I needed to choose a platform. Compiling to JavaScript would let me write my shared code (e.g. data models) once, rather than twice. It would also let me choose client-side vs. server-side execution as an implementation detail, rather as a major architectural decision. (That’s also a major reason why node.js is so popular.)

      What’s more, designing Kotlin to be cross-compiled from the beginning means that they don’t accidentally design the language to be uncompilable outside of the JVM. It’s analogous to writing cross-platform SQL but only testing on one database. (I did that once; it took months to port from MySQL to PostgreSQL.)

  5. platformStatic for function is nice, is there any equivalent for properties?

  6. Jason says:

    One of the main reasons we were evaluating Kotlin was its approach to null. The small syntax tax on working with nullables was a *feature*, not a bug. The fact that Java interop is common doesn’t change the fact that nullable values are dangerous and should be handled with care. Now I have to go back to always wondering if a deref is going to blow up with an NPE, and that sucks.

    It would have been far better to just make Kotlin aware of @Nullable and friends, and then stick to its guns.

    • @Nullable and friends will be back. We’re going to add extra diagnostics, as warnings by default, but you’ll have an option of lifting them to errors, if you want something along the lines of the old behavior.

      Note: there’s no really safe approach apart from not calling any Java code. Generics always mask nullability issues, because there’s no sensible runtime validation for whether an array of a collection contains nulls or not. The approach we had before looked very strict, but wasn’t really: Java could always trick you into an NPE. So it can now and will be able to no matter what we do.

      • I also see the loss of explicit null checking for Java interop as a big loss, not a gain. I had hoped that with help of kannotator needless checks of Java code could be minimized by adding external annotations to existing libraries. As I now understand kannotator is “obsolete”, and we have to accept all interop can cause npe’s everywhere. As there is quite a lot more Java code than Kotlin code that is really… everywhere… and that much reduces the usability of Kotlin’s compile time null checking.
        The “generics always mask nullability issues” remark I do not get, because at runtime it’s quite easy to see those nulls, hence the NPE’s 😉 I assume you mean compile time? I think this is solvable too with Java 8’s type annotations where you can mark the type as nonnull. Eclipse’s Luna compiler does this:

        http://www.slideshare.net/eclipsedayindia/annotation-based-null-analysis-in-eclipse-jdt

        • Unfortuneately, the external annotations approach does not really solve the interop problems. And, despite the ability to manually mark generic arguments as not-null, automatic tools are not great at inferring these.

          Thus, we can’t rely on this approach when it comes to compile-time errors. But what we can and will do is issue warning instead (and if you feel brave enough, you can elevate them to errors). This will give us a reasonable balance between safety and pragmatism.

          One remark about Java code being overwhelmingly more widespread than Kotlin code: this is true, of course, but our experience shows that even in the current state of the affairs (Kotlin issuing no nullability warnings) Kotlin’s null-checking is extremely useful in mixed codebases, because all the business logic in such projects is written in Kotlin, and the programmer can express her intentions regarding nulls in the type system.

          • Micah Zoltu says:

            How (in IntelliJ) can I change the behavior back to the old way of requiring me to explicitly deal with nulls on all variables coming from a Java call?

          • You just need to wait. Warnings and some more precise types will be put back shortly.

          • Micah Zoltu says:

            Last try with HTML comments before I give up, please delete the others if possible (and add a preview button to comments) 😀

            In the example:
            val x = javaMethodThatReturnsAString()
            fun Foo(input: String?) { }
            fun Bar(input: String) { }
            Foo(x)
            Bar(x) // SHOULD NOT COMPILE!

            Based on this article and the documentation, M9 changed the behavior here such that Bar(x) will compile. What can I do to tell the Kotlin compiler to go back to the old strict behavior requiring me to deal with possible null values?

            I want a compiler error not a runtime error! (cannot put enough emphasis on this) As you mentioned, any Java method can return null for reference types and I want the compiler to warn me of any place where I am not explicitly dealing with that situation.

            I can appreciate that this requires writing more code, but sometimes writing good/reliable software requires writing more code. The number one thing that attracted me to Kotlin was the not-null reference types and I feel like this change throws that largely out the window since the compiler can’t actually assure me that I am not passing around nulls. Before M9 it would force me to deal with them at all of the Java-Kotlin interop points which is exactly the behavior I desire.

            Andrey said this in a post above: “We’re going to add extra diagnostics, as warnings by default, but you’ll have an option of lifting them to errors, if you want something along the lines of the old behavior” and I wanted to know how to get errors.

            Also, I would be curious to hear more about how Java can sneak around the compiler checks with generics. Andrey mentions, “Generics always mask nullability issues, because there’s no sensible runtime validation for whether an array of a collection contains nulls or not” but that suggests to me that Kotlin is making assumptions about Java collections.

            Kotlin should assume all Java collections are like Array(T?) and never Array(T). Kotlin could then provide null stripping filters that can transform the Java provided Array(T) into Array(T?). You also shouldn’t be allowed to give an Array(T) to a Java method, you must give it an Array(T?). This would again give you compile time validation that the user was correctly copying the contents to a nullable array, or using a nullable array throughout their application.

            Finally, immutable collections would not be limited quite as much. If you get an ImmutableStack(T) from Java you still must assume it is really ImmutableStack(T?), but it is safe to pass an ImmutableStack(T) to a method that takes ImmutableStack(T?), since the Java method can’t mutate the stack you don’t have to worry about it putting a null into your collection.

            In general, I believe the perceived problem of Java being able to get around null checking in Kotlin is due to Kotlin making incorrect assumptions about Java code behavior. A compiler switch that alters the set of assumptions is fine with me, I just believe there needs to be a way to go into strict mode where Kotlin assumes every Java method is doing the worst thing possible.

            • Warnings are coming in the next milestone.

              Andrey mentions, “Generics always mask nullability issues, because there’s no sensible runtime validation for whether an array of a collection contains nulls or not” but that suggests to me that Kotlin is making assumptions about Java collections.

              The point is exactly that Kotlin can not make such assumptions, because those can not be checked at runtime.
              When I have a List<String> from Java, there’s no performant way to know at runtime whether it is a List<String?> or just List<String>. This was never working properly, because it can’t, and now we don’t even pretend that it does.

              Your reasoning about immutable collections is correct, but rather ad hoc. Generics are not only collections, and only so much in the language can be sensibly dedicated to collection-related special cases. In general, mutability has nothing to do with soundness of passing Foo<T> where Foo<T?> is expected. The relevant property is co-variance, and Kotlin supports it as a first-class concept, while Java does not.

              • Micah Zoltu says:

                Perhaps the piece I am missing is: What is the problem with Kotlin assuming that all generics (not just collections) of type “T” are really generics of type “T?”

                It is probably best if I want until the next milestone and play around with the behavior myself to better understand. I think the piece that I am stumbling on is that Kotlin doesn’t really have any BCL of its own. Everything is built on Java. This means that when I have what I think is a Kotlin collection, I really have a Java collection. This means that even if I had a filter that dropped nulls from the collection, the filter would still just be returning another Java collection and Kotlin is back in the same position it started in. This problem exists with R#’s null checking and enumerables, even if you clear the enumerable of nulls, R# can’t give a strong guarantee that the collection is null-free because I am still returning a C# collection from the filter which doesn’t understand not-null.

              • Perhaps the piece I am missing is: What is the problem with Kotlin assuming that all generics (not just collections) of type “T” are really generics of type “T?”

                This would mean that if you have an ArrayList<String>, all you can get from it is String?, and this is very inconvenient.

                About null-filtering: there are special methods for that in our standard library.

              • Micah Zoltu says:

                Yes, it is inconvenient, but I don’t write in static languages for convenience, I write in them because the compiler can prove things for me which allows me to reason about my code easier. To me, being able to reason about my code and have the compiler prove as much as it can about my program before the code is ever executed is far more important than saving me the effort of having to do null checks. If I were willing to accept the possibility of nulls everywhere I would write in JavaScript or Ruby, where there are no guarantees that anything is in a sane state.

                As I mentioned though, the underlying problem I’m guessing is due to the fact that Kotlin has no collections of its own, so there is no way to have a Kotlin Array since that just resolves to a Java/JavaScript Array. This means that by extension, all Kotlin Array are really Array which is unfortunate.

                I think until Kotlin has a collection library of its own (is this even on the roadmap?) we are left having to choose between two evils. As mentioned above, I would rather have to run every one of my collections through a null filter and get compile-time null checking (this is what I do in C#) than be left having to trust that no one put a null into my collection.

                If the compiler does force all Java generics to be of nullable types (perhaps via compiler switches as mentioned) then users can write Kotlin wrappers around the Java generics that provide more assertions such as was done here for C# not-null collections: https://github.com/Zoltu/Zoltu.Collections.Generic.NotNull and https://github.com/Zoltu/Zoltu.Linq.NotNull

              • Yes, it is inconvenient, but I don’t write in static languages for convenience
                You are rather unique in this regard, I think.

                To me, being able to reason about my code and have the compiler prove as much as it can about my program before the code is ever executed is far more important than saving me the effort of having to do null checks

                You must be very interested in dependently typed languages then.

                Having or not having Kotlin’s own collections is not very relevant, because if you use a Java collection only from Kotlin, the compiler will keep you safe: use kotlin.List as your type (not java.util.ArrayList), and you are fine. If interop doesn’t concern you, there are no problems whatsoever. If it does concern you, though, Kotlin’s own collections will a) be a disaster (see Scala), b) will not save you, because when you get a hypothetical KotlinList<String> from Java, you have no idea, whether it is actually KotlinList<String?> or KotlinList<String>

  7. Michael Rush says:

    I think “seemingless” at the end of the second paragraph is a typo? (Should be “seamless”)

Comments are closed.