Language Changes

NOTE: Some of the changes below are breaking changes, meaning that some code that was compilable with earlier versions will not compile any more, so you’ll need to correct it.

Platform Types

As we mentioned before, platform interoperability (i.e. Java and JavaScript interoperability) is among our top priorities, because this is so for our users. Nullability issues when interoperating with Java were one of the biggest complaints we were getting. In a nutshell, the problem is that any reference coming from Java may be null, and Kotlin, being null-safe by design, forced the user to null-check every Java value, or use safe calls (?.) or not-null assertions (!!). Those being very handy features in the pure Kotlin world, tend to turn into a disaster when you have to use them too often in the Kotlin/Java setting. We relied on external annotations and KAnnotator to mitigate this problem by enhancing Java with extra type information. This approach proves to be too cumbersome and doesn’t work for some cases.

This is why we took a radical approach and made Kotlin’s type system more relaxed when is comes to Java interop: now references coming from Java have specially marked types (we call them “platform types”, because they come from the underlying platform), which are treated specially:

Kotlin does not enforce null-safety for platfrom types. I.e. for Java values you get Java’s semantics: NPE is now possible for values coming from Java

1

2

vals=javaMethod()// s has a platform type

s.foo()// this line may throw NPE, like in Java

Platform types can not be mentioned explicitly in Kotlin code, but when the IDE/Compiler shows you type information, they are distinguished by exclamation marks at the end. Examples: String!, ArrayList<Int!>!, (Mutable)Collection<Foo!>!.

To store platform values, you can either rely on the type inference, or pick Kotlin types (either nullable or not, as you please):

1

2

3

vals=javaMethod()// platform type inferred

val s1:String=javaMethod()// not-null type chosen by the programmer

val s2:String?=javaMethod()// nullable type chosen by the programmer

When you assign a platform value to a non-null type, Kotlin emits assertions in the byte code so that to make sure that a non-null variable doesn’t hold a null, this keeps most nulls from propagating through the code. So, there may be an assertion error on line 2 in this example, instead of an NPE some time later.

When you override Java methods, again, you can not mention platform types, so you have to pick some Kotlin types instead:

1

2

3

4

5

6

7

8

9

classKotlinClass:JavaClass(){

// declared in Java as 'List<String> javaMethod(String s)'

override fun javaMethod(p1:String):List<String>{...}

// or it could be

override fun javaMethod(p1:String?):MutableList<String?>?

// or any other combination of nullabilities and collection mutability

}

To summarize, platform types relax Kotlin’s type system for the case of things coming from Java. When you are using Java libraries, Kotlin is as safe as Java. When there’s no Java involved, Kotlin is even safer: it guarantees absence of NullPointerExceptions. In the future, we are planning to enhance diagnostics on platform types so that Kotlin will issue warnings on misuse of nulls in the Java interoperability cases.

More on Platform Interop

We already covered in detail the changes introduced for better platform interoperability, but just to recap, we have introduced the platformStatic annotation to define methods as static when being called from Java, as well as a series of improvements for better dealing with getters, setters and other interop aspects.

No more local object declarations

As of M9, named objects can no longer be local. To use an object inside a function we need to use object expressions, i.e. assign an unnamed object to a variable:

1

2

3

4

5

fun usingObjects(){

val configuration=object{

val maxRows=10

}

}

The reason for this is that named objects in Kotlin are meant for representing singletons. Having these inside functions, which can be called several times makes little sense. Named objects can still exist if they are global or nested in non-inner classes.

Non-local returns

When working with higher-order inline functions we can now do non-local returns:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

inline fun using(closeable:Closeable,body:()->Unit){

try{

body()

}finally{

closeable.close()

}

}

fun processStream(stream:InputStream){

using(stream){

if(stream.read()==42)

return// exits processStream

}

}

Calling return from inside the function being passed to using, will exit the outer function processStream. In the case where the return type of processStream is different to Unit, the return must also provide a value.

Type is no longer a keyword

We can now use the word type as an identifier as it’s no longer a keyword.

Unit is now a named object

What used to be called Unit.VALUE is now called simple Unit.

Foo.instance$ becomes Foo.INSTANCE$

In the Java code we used to access Kotlin’s singletons (named objects) as Foo.instance$, now it’s Foo.INSTANCE$.
Similarly for class objects: was C.object$, now C.OBJECT$.

Incremental Builds

Kotlin’s goal has always been to be as fast as Java, and while we’re not there yet, we have taken one major step, and that is to provide incremental builds. In IntelliJ IDEA, we can toggle this option via a checkbox under Kotlin Compiler options:

NOTE that this feature is experimental. If something doesn’t work correctly, run Rebuild Project. Bug reports are appreciated.

You can also enable making projects automatically under Compiler options:

JavaScript support

We’ve been spending a lot of effort on the JavaScript backend, sorting out language issues and bringing the standard library up to part with the Java equivalent (to the extent possible). As such, code like the following now works when targeting JavaScript:

1

2

3

4

5

val cars=listOf("Ford","Audi","Skoda","Toyota","Jeep")

cars.filter{it.contains("o")}

cars.forEach{

println(it)

}

In addition to improving the standard library, we’ve also improved language support, now allowing for

IntelliJ IDEA improvements

Kotlin plugin for IntelliJ IDEA also has some new features and improvements.

Extract Function Refactoring and Code Duplication

Extract function now offers code duplication detection

prompting us to replace similar code occurrences with the the function we’ve just extracted.

Create From Usage

Long-time awaited, especially for those of us that do TDD once in a while, is the Create From Usage intention. We can now create functions based on usage, and even extension functions

Modules

Up to recently, Kotlin would treat any module’s symbols or any library referenced from a project anywhere, visible to the entire project. For instance, if we have three modules:

Ordering

Invoicing

Shipping

Invoicing and Shipping depend on Ordering, but do not on each other, up to now, in the IDE, completion and autoimport would still show symbols from all modules in all modules.
As of M9, it will only show symbols from those modules that are dependant.

Find and Rename by Convention

Kotlin allows for operator overloading. For instance, we can overload the + by creating a function named plus. Now, when renaming these, IntelliJ IDEA will automatically rename all corresponding usages.

Much the same thing will happen when moving from it to explicit arguments in lambda expressions.

Other IDE improvements

In addition, there are some other improvements. In particular

Debugger. Now supports delegated properties.

Completion. Overall improvements in completion in addition to completion for as when expected types are known at the point of invocation

Expand selection. Offering pretty much all the same functionality we currently have for Java

Summary

M9 is an important milestone, primarily because of the platform types. For us it’s really important to get feedback to determine whether these changes are in the right direction and if they’re making interop easier. So please try it out and let us know.

To install M9, update the plugin in your IntelliJ IDEA 13.1 or 14 EAP, and as always you can find the plugin in our plugin repository.NOTE you may need to invalidate caches of the IDE and/or rebuild your project.

How come the 0.9+ jars aren’t in Maven? Even with SNAPSHOT intellij is complaining about the version.

By the way, I think this was a great decision as sometimes the nullability issue was a workflow killer. But I would also like to see some nullability analysis tools or ways to detect platform nullable classes.

I am curious if it could be done in Gradle. It’s not so much incremental compile which it has to some extent (at least on a task by task basis) but instead for some sort of polling to see which files have changed and compile them in the background. This could also be done by intellij invoking gradle tasks when a file has been added/updated/deleted.

Any chance of incorporating some sort of real time evaluator like in light table?

We’ll be looking into the possibilities with Gradle, but I’m not sure if this is going to work.

About “real time evaluator”, it’s hard to tell. We have done some work in this direction in the debugger, but it’s a little different from what LightTable has. Doing inline evaluation for a static language would be something of a breakthrough…