Kotlin M3 is Out!

Andrey Breslav

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!

Comments below can no longer be edited.

23 Responses to Kotlin M3 is Out!

  1. Eugene Burmako says:

    September 20, 2012

    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

    • Andrey Breslav says:

      September 20, 2012

      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.

      • Eugene Burmako says:

        September 21, 2012

        Btw why not macros? For example, case classes can be easily implemented with macro annotations, thus saving you from introducing a new language concept + getting rid of a syntactic irregularity.

        • Andrey Breslav says:

          September 21, 2012

          There’s no new language concept involved, and no syntactic irregularity. “data” is an annotation (you can view it as a macro if you like). All annotations require [] in local scope. All annotations are processed by compiler or its plugins.

          • Eugene Burmako says:

            September 22, 2012

            Interesting! How far can one go with these annotations? Could you show an example?

          • Andrey Breslav says:

            September 22, 2012

            If you are interested in things like code transformations, then the answer is “you can do anything, but currently nothing is very easy to do”.

      • Eugene Burmako says:

        September 21, 2012

        Also how does one subscribe to comments?

  2. phil swenson says:

    September 20, 2012

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

    • Andrey Breslav says:

      September 20, 2012

      Kotlin is compiled to JVM byte codes (or JavaScript source code).

  3. soren says:

    September 21, 2012

    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:

    September 23, 2012

    Great stuff!

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

    • Andrey Breslav says:

      September 24, 2012

      In general, interoperate with Scala from Kotlin is as easy as from Java. The IDE support is not really integrated yet, though.

  5. someone says:

    September 24, 2012

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

    • Andrey Breslav says:

      September 25, 2012

      Could you provide some more details? Thanks

      • someone says:

        September 26, 2012

        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{0x00000001 / 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:

    September 25, 2012

    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?

    • Andrey Breslav says:

      September 25, 2012

      You are right, they are redundant.

  7. Kotlin Tester says:

    September 29, 2012

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

    A quite happy tester.

    • Andrey Breslav says:

      September 30, 2012

      We will do our best… 🙂

    • Vladimir Krivosheev says:

      October 4, 2012

      I am agree with you and I hope, I have fixed some of the current problems in my fork (it seems it will be integrated to m4).

      Please look https://gist.github.com/3832660 Is it ugly or not?

      Also, there is hidden (undocumented) feature — compiler can produce ecma3 or ecma5 javascript (add to in your iml).