Kotlin M3 is Out!

Last time I wrote about a new exciting feature in “the upcoming Kotlin M3″. Today, Kotlin M3 is not “upcoming” any more, it’s here. This post gives an overview of the new milestone.

We have redesigned kotlin.jetbrains.org. Currently, links from this page point to the familiar docs in our wiki, but this will also improve over time.

Improvements and Bug fixes

Many of almost 400 issues we closed in this milestone are bug fixes and small enhancements that make Kotlin neater and shinier. A huge improvement has been made in the type argument inference algorithm. It’s not finished yet, but is rather good already.

In M3 we started to profile things and tune performance of the IDE as well as the compiler. It will be a lot of work, but eventually everything will be fast and consume little memory. This time most improvements are related to code completion.

Multi-assignment and Data Classes

This is covered in the last week’s entry. Long story short, you can write things like this:

val map = hashMap("one" to 1, "two" to 2, "three" to 3)
for ((k, v) in map) {
    println("$k -> $v")
}

And define data classes like this:

data class Point(val x: Int, val y: Int)

Here Point automatically gets toString(), equals()/hashCode() and component functions that enable you to write this:

val (x, y) = functionReturningPoint()

See more in the aforementioned post.

These features enabled us to deprecate tuples. They will be removed completely in the next milestone, and you can migrate your code automatically using the IDE plugin.

Collections

Static JVM languages tend to come up with their own collections libraries, because Java collections do not make use of the cool features these languages have. So we get really cool collections, that are, unfortunately, incompatible, which makes us wrap them or copy when using Java APIs.

Kotlin has many fancy features, but we are eager to interoperate smoothly with Java, and, it turns out, we can have this cake and eat it too. Meet Kotlin’s collections:

As you can see, the basic structure here is very much like what java.util gives us, but with a few important differences:

  • There are traits (“interfaces”) that distinguish between mutable and read-only collections.
  • Read-only traits (like List or Set) are covariant (i.e. you can assign a List<String> to a List<Any>).

The good old java.util.ArrayList is still there, but Kotlin sees it as if it inherited from Kotlin’s MutableList, which in turn inherits List. This way you get both compatibility and nice type properties for your collections, like being able to pass a List<String> where List<Any> was expected.

Note that since the old names (like List or Collection) now mean something different, some of your code will break. For a quick and dirty solution, you can change all your Lists to MutableLists and so on, but it would be better if most of your data were read-only.

Also note that if your old code imported something like java.util.Collection, you will get a warning on this import, and will need to remove it.

External annotations

Kotlin makes your programs safer by incorporating null-safety into the type system. Since Java doesn’t care that much about this, we need to guard against it by asserting that things returned from Java are not null using the ‘!!’ operator:

if (file.getName()!!.endsWith(extension)) {...}

(BTW, the good old sure() function has been removed from the library, and you can migrate your code automatically.)

Many Java methods never actually return null. People use annotations to let the tools know about it, but what if I’m using a third-party library?

In Kotlin M3 we support external annotations: you can annotate things even if you don’t control their source code. This is done easily in the IDE.

We’re going to create an automated tool that will infer the annotations from the library code. Until then, we use the IDE to add annotations manually.

Local Functions and Classes

In addition to local functions, Kotlin M3 support local classes and object declarations:

fun foo() {
  class Bar {...}
  val bars = ArrayList<Bar>()
  // ...
}

Note that to create a local data class, you need to surround the “data” annotation with square brackets:

fun foo() {
    [data] class Data(...)
    // ...
}

Java Interoperability: Enums and Annotations

Support for annotations in Kotlin has been improved greatly. Among other things, Kotlin’s annotations are now fully compatible with Java annotations, one can use enum constants in annotations’ argument lists and so on.

Enums are also much better now: they support valueOf(), name() and ordinal() and play well with Java.

REPL/Scripts

We have done some work on supporting scripts in Kotlin. Script support is rather preliminary, but you can run something like this:

// tree.ktscript
import java.io.File

fun tree(dir: File, indent: String) {
    val files = dir.listFiles()!!
    for (file in files) {
        println(indent + file!!.getName())
        if (file.isDirectory()) {
            tree(file, indent + "  ")
        }
    }
}

tree(File("."), "")

By calling it from the command line:

$ kotlinc/bin/kotlinc-jvm -script tree.ktscript
foo
  bar.txt
tree.ktscript

Shebang” comments are supported as well.

Scripts get us close enough to having a REPL, but we are not there yet. Please, use Web Demo instead.

Have a Nice Kotlin!

The new plugin requires IntelliJ IDEA 12, which is available as an EAP build (this version of IntelliJ IDEA is not released yet, there are problems, e.g. this issue with Android). And don’t forget to update your kotlin-runitme.jar (the IDE will offer you to do so)!

As usual, your feedback is very welcome!

About Andrey Breslav

Andrey is the lead language designer working on Project Kotlin at JetBrains. He also works on making the Java language better, serving as a Java Community Process expert in a group for JSR-335 ("Project Lambda"), and occasionally speak at software conferences such as Devoxx or JavaOne.
This entry was posted in General and tagged . Bookmark the permalink.

23 Responses to Kotlin M3 is Out!

  1. Hi Andrey,

    It’s great to see you guys making progress with Kotlin. As you can guess, I’ve got some questions :)

    1) What has your experience shown w.r.t pattern matching? Have you uncovered important uses cases for it or, to the contrast, grew in your opinion that it’s redundant?

    2) What’s the progress with first-class arrays? Is it possible to create an array of a type that depends on a generic parameter? Also, have you found a way to avoid boxing in generic setting?

    3) Local classes. Can one return instances of local classes from methods? If yes, can one do that for methods with inferred return types? What type gets inferred in that case?

    4) [data] in local classes. Would be interesting to find out why this requires brackets? Ambiguities in parser?

    Good luck with Kotlin!

    Cheers,
    Eugene

    • Hi Eugene, thanks for the kind words!

      1) We still think we can easily live without it. Especially so for people who do not write compilers :)
      2) Didn’t work on this. We consider arrays as a low-level tool, thus not much plans on investing in making them, very beautiful.
      3) Yes, but not from method with inferred return type (in fact, this would be even syntactically rather difficult to achieve).
      4) Yes, parser. We refrain from adding many keywords. Stuff like ‘public’ or ‘data’ is regarded as annotations, thus there are conflicts in local scopes.

  2. phil swenson says:

    With regards to scripting and repl. Is Kotlin interpreted or compiled?

  3. soren says:

    Here’s a few things you may(or may not) find interesting that I’d like to bring to your attention.

    To compare Kotlin to other languages on “scriptability”

    Scriptometer: measuring the ease of SOP (Script-Oriented Programming) of programming languages
    http://rigaux.org/language-study/scripting-language/

    I think a “structured editing” mode would be nice because curly braces take up so much screen real estate. If not in the main IDE, I think a nice project would be a Kotlin scripting environment/editor featuring structured editing. It may appeal to python programmers who like their significant white-space.

    http://blogs.msdn.com/b/kirillosenkov/archive/2009/09/08/first-videos-of-the-structured-editor-prototype.aspx
    http://www.guilabs.net/

    Google’s Java to Objective-C translator is worth watching. Personally I think Ahead of Time compilation is a better solution but that’s not going to happen for a while… and if it does Oracle may try to limit developers to using JavaFX.

    https://code.google.com/p/j2objc/

  4. Ali says:

    Great stuff!

    Are there any plans for interoperability with existing Scala code as well?

  5. someone says:

    Hi.
    I have some problems similar to http://youtrack.jetbrains.com/issue/KT-2044 after M3.

    • Could you provide some more details? Thanks

      • someone says:

        I’m developing an android app with kotlin.
        It compiled well , but the dexing fails.

        This is the sample code.
        private fun doTest() : Int {
        var list : MutableList? ;
        try {
        list = ArrayList()
        list?.add(3)
        return 0 ;
        }
        finally {
        if(list != null) {
        Log.d(“aaa” , “list size : ” + list?.size() )
        }
        }
        }

        And error message.
        [dx] EXCEPTION FROM SIMULATION:
        [dx] local 0001: invalid
        [dx]
        [dx] …at bytecode offset 000000a8
        [dx] locals[0000]: Lcom/example/helloworld/HelloKotlin;
        [dx] locals[0001]:
        [dx] locals[0002]:
        [dx] locals[0003]: type{java.lang.Object}
        [dx] stack[top0]: int{0×00000001 / 1}
        [dx] …while working on block 00a6
        [dx] …while working on method doTest:()I
        [dx] …while processing doTest ()I
        [dx] …while processing com/example/helloworld/HelloKotlin.class
        [dx]
        [dx] 1 error; aborting

        If I initialize list with null , dexing succeed.

  6. Neil Galarneau says:

    I’m glad to hear about the repl & scripts features.

    In the script example, there are 3 uses of the !! operator on the ‘file’ loop variable.

    Are the second & third uses redundant? In other words, if ‘file’ is null, won’t the first ‘file!!’ throw an NPE and therefore execution could never reach the second or third ‘file!!’ expressions? (the !! operator behaves like a null check)

    Or is the compiler not able to deduce that yet?

  7. Kotlin Tester says:

    Hi Kotlin guys!
    Your example “A multi-language Hello” generates ugly JS code, will this be improved soon?
    Thanks.

    A quite happy tester.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>