M10 is out

Posted on by Hadi Hariri

Right before the festivities start, we’ve managed to release the next milestone of Kotlin, adding dynamic types and more. Let’s see what M10 brings us.

Language enhancements

Some improvements in the language, in particular:

Reified type parameters for inline functions

Before M10, we sometimes wrote code like this:

fun  TreeNode.findParentOfType(clazz: Class): T? {
    var p = parent
    while (p != null && !clazz.isInstance(p)) {
        p = p?.parent
    }
    return p as T
}

Here, we walk up a tree and use reflection to check if a node has a certain type. It’s all fine, but the call site looks a little messy:

myTree.findParentOfType(javaClass())

What we actually want is simply pass a type to this function, i.e. call is like this:

myTree.findParentOfType()

But then we’d need reified generics to access that type inside a function, and on the JVM reified generics are expensive…

Fortunately, Kotlin has inline functions, and they now support reified type parameters, so we can write something like this:

inline fun  TreeNode.findParentOfType(): T? {
    var p = parent
    while (p != null && p !is T) {
        p = p?.parent
    }
    return p as T
}

We qualified the type parameter with the reified modifier, now it’s accessible inside the function, almost as if it were a normal class. Since the function is inlined, no reflection is needed, normal operators like !is are working now. Also, we can call it as mentioned above: myTree.findParentOfType<MyTreeNodeType>().

Though reflection may not be needed in many cases, we can still use it with a reified type parameter: javaClass() gives us access to it:

inline fun methodsOf() = javaClass().getMethods()

fun main(s: Array) {
  println(methodsOf().joinToString("\n"))
}

Normal functions (not marked as inline) can not have reified parameters. A type that does not have a run-time representation (e.g. a non-reified type parameter or a fictitious type like Nothing) can not be used as an argument for a reified type parameter.

This feature is intended to simplify code in frameworks that traditionally rely on reflection, and our internal experiments show that it’s working well.

Checks for declaration-site variance

Kotlin has declaration-site variance from the very beginning, but the correspondent checks have been missing from the compiler for a long time. Now they are put in their place: the compiler complains if we declare a type parameter as in or out, but misuse it in the class body:

class C {
  fun foo(t: T) {} // ERROR 
}

In this example, since T is declared as out (i.e. the class is covariant in T), we are not allowed to take it as a parameter to the foo() function, we can only return it.

Note that a private declaration is allowed to violate variance restrictions, for example:

class C(t: T) {
    private var foo: T = t
}

Although foo‘s setter takes T as as an argument, and thus violates the out restriction on it, the compiler allows this and makes sure that only the same instance of C has access to foo. This means that the following function in C would not compile:

// inside the class C
private fun copyTo(other: C) {
    other.foo = foo // ERROR: Can not access foo in another instance of C
}

This is a breaking change: some code that compiled previously may break, but not fixing it is likely to result in run-time exceptions anyways, so the compiler errors will be of some value to you 🙂

Type inference supports use-site variance

Type argument inference has been improved to accommodate use-site variance more comfortably. Now you can call a generic function, e.g. reverseInPlace() on a projected type, such as Array<out Number>:

fun example(a: Array) {
    a.reverseInPlace()
}

where reverseInPlace is defined as follows:

fun  Array.reverseInPlace() {
    fun (i in 0..size() / 2) {
        val tmp = this[i]
        this[i] = this[size - i - 1]
        this[size - i - 1] = tmp
    }
}

The underlying mechanism was proposed initially by Ross Tate in his paper on “Mixed-Site Variance”.

Varargs translated to projected arrays

Another breaking change comes in the form of a fix to a obscure, but sometimes rather annoying issue: when we have a function that takes a vararg of String?, we really want to be able to pass an array of String to it, don’t we? Before M10 it was impossible, because vararg of T were compiled to Array<T>, now they are compiled to Array<out T>, and the following code works:

fun takeVararg(vararg strings: String?) { ... }

val strs = array("a", "b", "c")
takeVararg(*strs)

JavaScript improvements and changes

JavaScript gets an important update in this version with support for dynamic types.

Dynamic support

Sometimes the best way to talk to dynamic languages is dynamically. This is why we’ve introduced the soft keyword dynamic which allows us to declare types as dynamic. Currently this is only supported when targeting JavaScript, not the JVM.

When interoperating with JavaScript we can now have functions take as parameters, or return, a dynamic type

fun interopJS(obj: dynamic): dynamic {
   ...
   return "any type"
}

We’ll cover dynamic in more details along with usage scenarios and limitations in a separate blog post. For technicalities see the spec document.

New Annotations

We’ve added a series of annotations to make JavaScript interop easier, in particular nativeInvoke, nativeGetter and nativeSetter.

If a function bar is annotated with nativeInvoke, its calls foo.bar() are translated to foo() in JavaScript. For example:

class Foo {
   nativeInvoke
   fun invoke(a: Int) {}
}

val f = Foo() 
f(1) // translates to f(1), not f.invoke(1)
f.invoke(1) // also translates to f(1)

Much the same way, we can use nativeGetter and nativeSetter to get index-access available in JavaScript:

native("Array")
class JsArray {
   nativeGetter
   fun get(i: Int): T = noImpl
   nativeSetter
   fun set(i: Int, v: T): Unit = noImpl
}

Without native* annotations, calls to get and set (including those done by convention, e.g. a[i] = j is the same as a.set(i, j)) are translated to a.get(...) and a.set(...), but with the annotations placed as above, they are translated to square brackets operator in JavaScript:

a[0] // translates to a[0], not a.get(0)
a.get("first") // translates to a["first"]
a[2] = 3 // translates to a[2] = 3

We can use these annotations in the following cases:

  • non-extension member functions of native declarations,
  • top-level extension functions.

Kotlin.js output – breaking change

Previously, when creating a new project, the kotlin.js runtime would be created in a folder named scripts. As of M10, this file is created on first compilation and is placed in the output folder (defaults to out). This provides for a much easier deployment scenario as library and project output is now located under the same root folder.

New no-stdlib option to kotlin-js compiler – breaking change

We now provide a command line option for the kotlin-js compiler, namely no-stdlib. Without specifying this option, the compiler uses the bundled standard library. This is a change of behaviour from M9.

js code

We can now output JavaScript code directly inside Kotlin code

js("var value = document.getElementById('item')")

which takes the code provided as parameter and injects it directly into the AST JavaScript code that the compiler generates.

As you can see, we’ve added a lot of new improvements for JavaScript in this release and we’ll cover these in more detail in a separate post.

Java Interop

[platformStatic] for properties

Now, we can mark properties as [platformStatic] so that their accessors become visible from Java as static methods.

Static fields in objects

Properties on any object now produce static fields so that they can easily be consumed from Java even without the need to decorate them with platformStatic annotations.

JNI and [native]

Kotlin now supports JNI via [native] annotation, defined in kotlin.jvm package (see the spec document here.). To declare a native method, simply put the annotation on it:

import kotlin.jvm.*
import kotlin.platform.*

class NativeExample {
    native fun foo() // native method

    class object {
        platformStatic native fun bar() // static native method
    }
}

Here’s an example of using native declarations with Android and NDK.

IntelliJ IDEA improvements

Some more improvements in the IntelliJ IDEA area, including:

Incremental compilation in mixed projects

We’ve enhanced incremental compilation and with M10 it now supports dependencies between Kotlin and Java code. Now when you change your Java code, the relevant parts of your Kotlin code are re-compiled. As a reminder, incremental compilation is activated under the Kotlin Compiler options.

HotSwap fixed in debugger

Now, when we recompile Kotlin code while debugging it, it gets smoothly re-loaded into the debugee process.

Evaluate Expression: Completion improvements

During debug sessions, when evaluating expressions, casts are automatically added as needed. For instance when downcasting from Any to a specific type.

Completion Casts

Copy reference

We can now obtain the complete reference for any Kotlin symbol, much like we do with IntelliJ IDEA in Java code

Copy Reference

Create from usage for classes and packages

Create from usage is now available for classes and packages, which contributes significantly to a TDD workflow. Even if you’re not doing TDD, it does minimize friction of creating new elements.

Create Class from Usage

Generics in change signature

The Change Signature refactoring now supports generics in cases where a base class function is promoted to use generics. In essence, in the following scenario

open class Base {
    open fun baseMethod(t: T, k: K) {}
}

class Derived: Base> {
    override fun baseMethod(a: List, b: Y) {}
}

If the signature of Base.baseMethod is changed to baseMethod<T>(t: List<T>, k: K?) then the signature of Derived.baseMethod is appropriately changed to >baseMethod<Y>(a: List<Y>, b: List<X>?)

Completion improvements

Completions items ordering has been improved, immediate members are now highlighted. Smart completion now finds inheritors of expected types. Completion performance severely improved.

Runnable objects

Now you can run an object that declared a [platformStatic] main function, for the IDE:

import kotlin.platform.*

object Hello {
    platformStatic fun main(args: Array) {
        println("Hello")
    }
}

Just right-click the object and select Run …

Code Coverage highlighting in the Editor

If you run Kotlin code with coverage, the Editor now marks covered and uncovered lines for you (available in IntelliJ IDEA 14 only).

JavaScript project configuration

The IDE plugin can now automatically configure Maven projects to work with Kotlin/JS. Also, if you have an outdated version of Kotlin’s runtime library, the IDE will ask you to update it, and you can now chose to use a library located in the plugin distribution, instead of copying one into your project.

Summary

To install M10, update the plugin in your IntelliJ IDEA 14 (or earlier versions), and as always you can find the plugin in our plugin repository. You can also download the standalone compiler from the release page.

Comments below can no longer be edited.

28 Responses to M10 is out

  1. Jon Renner says:

    December 17, 2014

    I’m curious, why were properties like Array.size deprecated in favor of the method Array.size()?

    • Andrey Breslav says:

      December 17, 2014

      The reason is uniformity: collections have the size() function, because Java APIs are designed this way, and we decided to make arrays as close to collections as possible

      • Jon Renner says:

        December 18, 2014

        I think this is a good reason

  2. The Bitcoin Developer Guide, Plumbr locked threat detection and JetBrains Kotlin M10—SD Times news digest: Dec. 17, 2014 - SD Times says:

    December 18, 2014

    […] More information on all the new features in Kotlin M10 is available here. […]

  3. Kotlin M10 发布,基于 JVM 的编程语言 | 我爱互联网 says:

    December 18, 2014

    […] 此版本现已提供下载,更多内容请看发行说明。 […]

  4. Paweł Gajda says:

    December 18, 2014

    reifying is awesome… time create new inlines

  5. The Bitcoin Developer Guide, Plumbr locked thread detection and JetBrains Kotlin M10—SD Times news digest: Dec. 17, 2014 - SD Times says:

    December 18, 2014

    […] More information on all the new features in Kotlin M10 is available here. […]

  6. Dmitry says:

    December 18, 2014

    1. There used to be a handy constructor for Array – the one that took a size and a function that populates elements. Why was it deleted and what’s the way to construct a new array of given size, say, of type Array? Only creating it using arrayOfNulls, manually populating it and then casting it to be not nullable?
    2. Why there are functions listOf(), arrayListOf() and so on, but corresponding function for arrays is array(), not arrayOf()?

    • Dmitry says:

      December 19, 2014

      Ok, the 1st one is not an issue – in the beginning I’ve updated the plugin but haven’t updated kotlin version in pom.xml.

    • Andrey Breslav says:

      December 22, 2014

      The array function naming is different for historical reasons only. Will be fixed

  7. Paweł Gajda says:

    December 20, 2014

    Still missing extracting future in IntelliJ Editor. For functional programming it’s a killer missing feature.

  8. Andrey says:

    December 20, 2014

    I have a function with signature:
    inline fun enum<reified T: Enum>() {}
    and it works fine. But when I add some arguments, e.g.:

    inline fun enum<reified T: Enum>(a: Int = 1)

    it fails at run time with the following message: java.lang.UnsupportedOperationException: You should not use functions with reified parameter without inline

    Is that correct behaviour?

  9. Dan says:

    December 29, 2014

    Is there any plan to support dynamic on the JVM?

    • Andrey Breslav says:

      December 29, 2014

      It is on the roadmap, but not a priority for now

      • Dan says:

        December 30, 2014

        Very cool!

  10. Farrukh Obaid says:

    January 26, 2015

    how to create javascript anonymous object in kotlin? i want to create exactly this
    var header = {“content-type”:”text/plain” , “content-length” : 50 ………}
    i have to pass this object in nodejs help me

    • Zalim Bashorov says:

      January 28, 2015

      Already answered on SO

  11. Julius Kunze says:

    February 18, 2015

    Why are semicolons optional but not commas in multi-line argument/parameter lists? What about

    fun main(args : Array) {
    println(User(
    id = 123
    email = “elon@x.com”
    name = “Elon”
    followers = listOf(
    User(email = “emma@a.com”)
    User(email = “steve@b.com”)
    User(email = “anna@c.com”)
    )
    isAdmin = true
    ))
    }

    public data class User(
    public val id: Long? = null
    public val email: String
    public val name: String? = null
    public val followers: List = listOf()
    public val isActive: Boolean = true
    public val isAdmin: Boolean = false
    )

    In my eyes this would remove redundancy while improving readability. Plus it would make multiple tasks faster:
    – Moving of initialized fields between constructor and class body
    – Reordering arguments/parameters (no comma/no-comma switch for the last entry)
    – Defining lists with long entries

    It should still be easy for the brain/compiler to distinguish between blocks and argument/parameter lists because of the different types of parentheses. Ambiguities with entry separation should be rare and the problem was nicely solved for instructions inside blocks.

    • Andrey Breslav says:

      February 18, 2015

      I’d say that this request is logical, but questionable, because, unlike statements, arguments are very often passed on a single line, and as code evolves, we migrate between two forms, thus the user (or a tool) would have to add/remove commas upon simple (and common) changes of formatting

      • Julius Kunze says:

        February 19, 2015

        I agree that this change is questionable. I still believe that it could result in a better language, mainly for the following reason: You read code much more often than you write it. That’s why all the tooling issues should not be weighted too heavy versus the improved readability caused by decreased comma noise.

        Anyhow, here are my thoughts about the tooling: In my experience argument/parameter list are most readable if all entries are on a single line or all entries are on different lines. What about providing a refactoring tool that converts any of those lists into one of those well-readable forms? For calls, an option to name all parameters at the same time would be cool!

        All cases would be well covered now:
        – Converting multi-line to single-line: Deleting the line break between two entries automatically inserts a comma before the cursor. Better and faster approach: Use the refactoring above.
        – Converting single-line to multi-line: Just use the refactoring above or: Inserting line breaks automatically removes redundant commas.
        – Removing redundant multi-line commas in existing code: This could be be part of the reformatting.
        – Writing a new single-line list: As before.
        – Writing a new multi-line list: Easier than before because no commas have to be provided.

        Independently: Thank you for making Kotlin! Combined with IntelliJ it is programmers dream. Keep up your great work.

        • Andrey Breslav says:

          February 19, 2015

          This makes a very common change of adding another parameter to a function call require a tool to assist you (otherwise it’s too tedious). This will annoy too many people for too little a benefit.

          • Julius Kunze says:

            February 20, 2015

            It’s hard for me to understand that relying on tools can annoy people. A task as simple as renaming a symbol without a tool is annoying, isn’t it?

            Nevertheless, I understand your decision now.

  12. Andrey Breslav says:

    March 11, 2015

    Я создал issue в нашем трекере: https://youtrack.jetbrains.com/issue/KT-6956, подпишитесь на нее, чтобы смотреть комментарии, и добавьте, пожалуйста, байткод, если он был в сообщении об ошибке. Спасибо!

  13. Roadmap de #kotlin | Kotlin.es says:

    August 22, 2015

    […] oficial en inglés, […]

  14. UnFroMage comments on "Why you might want to choose Ceylon" - Exploding Ads says:

    October 28, 2015

    […] > – reified generics — This is apparently expensive on the JVM: https://blog.jetbrains.com/kotlin/2014/12/m10-is-out/ […]

Subscribe

Subscribe for updates