The Great Syntactic Shift

As the first public preview of Kotlin is approaching (it will be announced on Jan 10th, 2012, which is less than a week from now!), we are putting some things in order…

In particular, we have reviewed syntactic forms available in the language, and decided to change a few. These changes are incompatible with the old syntax, and we have migrated all our test data, and will update the publicly available documentation soon.

I would like to point out that this is not the last change of this sort. Kotlin is not released yet, and until it is we are constantly gathering feedback and sometimes find out that something needs to be changed. Consequently, there are no backward-compatibility guarantees before the 1.0. We realize how important backward compatibility is, but we’d better be backward compatible to a really good design created according to the needs of real people.

Here’s an overview of the changes we’ve made.

The Namespace is dead. Long live the Package.

The concept of namespaces evolved into something so close to Java packages, that we decided to rename it. The namespace keyword is replaced by package keyword. Additionally, namespace blocks are no longer supported.

The Arrow loses weight

An arrow is used in function literals and when expressions. Some languages use a “fat arrow” (=>) and some use a “thin arrow” (->). Initially, we used the fat one, but is has some unfortunate interactions with comparisons, like this:

  val higherThanY  = {x => y <= x}

So we decided to switch to a thin arrow:

  val higherThanY  = {x -> y <= x}

More readable function types

In the old syntax we wrote function types as follows:

val f : fun(Int) : String

which is very close to Kotlin’s function declaration syntax, and seems perfectly logical. Unfortunately, as this feature starts interacting with others, things get a lot worse:

fun max(col : Collection<Int>, compare : fun(Int, Int) : Int) : Int 

Have you got lost in colons? Yes, me too…

So we decided to change the function type syntax to the following:

fun max(col : Collection<Int>, compare : (Int, Int) -> Int) : Int

And a little more

Additionally, we introduced optional parentheses in types, changed the tuple syntax to be distinguishable from parenthesized expression lists and made some minor (backward compatible) changes. All this will be reflected in the docs soon. As usual, your feedback is very welcome.

Stay tuned, and don’t miss the announcement next Tuesday!

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, Language design and tagged . Bookmark the permalink.

47 Responses to The Great Syntactic Shift

  1. Sergey Lukjanov says:

    It looks very good.
    Public preview == downloadable compiler?

  2. Alexander Kosenkov says:

    “The Great Syntactic Shift” -> “The First Great Syntactic Shift”
    Make it a bit easier for historians of the future!

  3. Do you plan to support Unicode characters in the source code?
    >= ≥


    But in current font in Idea those arrows don’t look readable. And additionally, UTF-8 must be default encoding in IDE to my taste.

    val higherThanY = {x ⇒ y ≤ x} // Even not so bad now!

    • I don’t have a ≥ key on my keyboard, so I don’t know how I’d benefit from such a thing in the code…

    • Ian Clarke says:

      I don’t think this is a good idea, in exchange for a little visual sugar you are going to cause all sorts of headaches for people with editors that have poor Unicode support, and for people with a poor understanding of Unicode.

      If in doubt, leave it out :-)

  4. Well, with Unicode support it might have been even not so bad:

    val higherThanY = {x ⇒ y ≤ x}
    val higherThanY = {x → y ≤ x}

    Just to show how ugly it looks now:
    val higherThanY = {x -> y <= x}

    I hope this needs just a tiny change in parser code and new option in Idea's Automcatic Code Formatting preferences.

  5. Will there be an IntelliJ plugin for the preview?

  6. Habfast says:

    Terrific!

    can’t wait to get my hands on the eclipse plugin, when it comes out (I have absolutely no knowledge of plugin coding for eclipse, but if no one is working on an eclipse plugin currently, I’m ready to get my hands dirty)

    • Sounds great! Feel free to contact me in regard to this: andrey dot breslav at jetbrains dot com

    • Ian Clarke says:

      An Eclipse plugin would be awesome, however be careful that you aren’t biting off more than you can chew. They’ve been working on an Eclipse plugin for Scala for several years, including several complete rewrites, and they still aren’t there yet. If you do plan on doing this you should research the design of the Scala Eclipse plugin.

  7. Pavel Trukhin says:

    Are you planning to release Kotlin plugin for Maven? If you’re not working on it, I am ready to offer my services to develop it (have some experience in this field).

    • Evgeny Goldin says:

      Hi Pavel,

      Many thanks for suggesting your services. I work on Kotlin integration with the build tools (Ant, Maven and Gradle are in the plans so far). Can you drop me a line (evgenyg at gmail) so that we’ll have your coordinates?

  8. Thin arrow VS fat arrow VS no arrow

    What if a ruby style for closures?

    val higherThanY = {|x| y <= x}

    • First of all, it doesn’t look pretty :)

      Then, parser recovery gets messier when using the same character as opening and closing parenthesis at the same time. And it is not really clear where to put the function return type in the complete form. And a short form (without braces) looks weird when takes no arguments…

  9. Alex Vas says:


    So we decided to change the function type syntax to the following:

    fun max(col : Collection, compare : (Int, Int) -> Int) : Int

    Humm… Is it supposed to be

    fun max(col : Collection, compare : (Int, Int) -> Int) -> Int

    or am I missing something?

    • The main reason for this change was getting read of repetitive commas that look like a mess. With the second option you refer to we get exactly the same.

      That’s why we changed only the function type syntax and not function declaration syntax, so that the first option you refer to is correct.

  10. Throwable says:

    Mathematically an expression (Int,Int) -> Int is correct and means “a map from set of Int*Int to integer set”. But I find that the arrow “->” looks a little ungly (like rest of mathematical symbols ;) , rather difficult to type and uncondence whole type declaration. The alternative way is to use more verbose notation for a functional type like Int(Int,Int). It means “Integer that depends on two parameters of integer type”.
    Thus:

    val str : String // declares a value of type String
    val f : String(Int,Int) // declares a function of type (Int,Int) -> String
    fun max(col : Collection, compare : Int(Int, Int) ) : Int
    val max : Int( col : Collection, compare : Int(Int, Int) ) // :)

    I think no one will confuse this syntax with a constructor call while it is used only where type declaration is required.

    • There are two things to remember here:

      First, a function type may describe an extension function, and thus might need to specify a receiver type. For example:

      val arr : MyArray = ...
      val get : MyArray.(Int) -> Int = ...
      val i = arr.get(10)

      Second, return types in Kotlin go after the declared element

    • Ian Clarke says:

      Personally I quite like (Int, Int) -> Int, and prefer it relative to Int(Int, Int).

  11. Otto Christian says:

    I was reading the dart website (this article: http://www.dartlang.org/articles/idiomatic-dart/) and one thing I was happy about top-level definitions, i.e. not having to put everything inside a class. This is something that annoys me in Java because often I have static functions (or fields) which don’t really fit in any class, but I have to put them in some class. It also makes classes a lot more confusing to read, because I end up with all these random static functions, fields, etc. mixed in with my classes.

    Does Kotlin allow top-level definitions of functions and fields? I probably missed it in the docs, but it wasn’t clear to me from skimming the docs.

    Whether you call it a namespace or a package, I don’t mind :)

  12. Stephen Colebourne says:

    I had great hopes from the title that you would be sorting the order of the type declarations. You’ve improved the colon confusion a little, but not enough to really make things suitable. The colon itself is the problem, caused by putting the type after the name. Remember that Scala users place the colon next to the variable name to help the colon disappear – its that bad.

    Don’t get me wrong, this is better than before:
    fun max(col : Collection, compare : (Int, Int) -> Int) : Int
    but, it still places too much emphasis on the colons and the hanging return type at the end. (the colon is larger than the comma, so your eye tends to divide by colon, not comma, which is wrong)

    And this always looks bad with default arguments, because it looks like the value is assigned to the type, not to the variable:
    fun max(str : String = “foo”) : Int

    Note that simply correcting the order doesn’t solve the problem either:
    fun Int max(Collection col, (Int, Int) -> Int compare)

    Remember the goal here is *readability* – and that requires the human brain to treat the type as a single unit when visually parsing (the human eye sees patterns, and the spaces and colons cause the pattern recognition to see different element parts, rather than whole elements). Compare these three:
    fun Int max(Collection col, (Int, Int) -> Int compare)
    fun Int max(Collection col, (Int, Int -> Int) compare)
    fun Int max(Collection col, {Int, Int -> Int} compare)

    Note how the eye can more easily group the elements to form a single type in the latter two. (When reading the signature, the first level of knowledge is that it is a function type – the types of the function type are second level knowledge).

    Now adjust it again, and you get something interesting:
    fun Int max(Collection col, Fn compare)

    A function is essentially a parameterization, so why not express it as such. (BTW you could continue with an arrow, but it doesn’t look as good). Note that this can be prefixed by “MyArray.” for the receiver type.
    val MyArray.Fn get = …

    My main point though is that it is really important to *group* the function type as a single element in the human eye, so that the brain parses it as a single unit (ie, some form of surrounding brackets). Otherwise, the brain has to re-associate the separate parts to form a whole type – and it is that which makes the language less readable.

    • Stephen Colebourne says:

      Darn blog eating HTML. The last two examples should be

      fun Int max(Collection col, Fn<Int, Int: Int> compare)

      val MyArray.Fn<Int, Int: Int> get = …

      • MuppetGate says:

        var s1 : String = s.toString()

        To me, at first glance, it looks as though something is being assigned to a String.

        var String s1 = s.toString()

        would be better IMO

    • Aivar says:

      This question (whether type should go before or after the name) is also related to what one considers more important — the name or the type? In Java I’m usually searching for name first and if the name doesn’t tell me the type then I’m reading the type expression.

    • MuppetGate says:

      I have to agree. It’s a lot easier to read and understand without the colons and with the type in front.

      This one:

      fun Int max(Collection col, {Int, Int -> Int} compare)

      is clearest declaration in my opinion, but you’re right: the colons are too distracting.

      I hope Jetbrains take a look at this.

      • Det says:

        Interesting, I do not agree here.

        What you consider clearest declaration is in no way best for me, although indeed the best for leading types.

        Stephen Colebourne
        > (the colon is larger than the comma, so your eye tends to divide by colon, not comma, which is wrong)

        Then your eye must be trained different to mine. My eye tends to separate on comma, while the colon is kind of glueing two things for me. Much more as I tend to add a space to the comma, but not to the colon.
        So in
        (some:thing, other:thing)
        I feel a strong binding of some to thing, what I do not feel in
        (some thing, other thing)

        That is too, why I tend to misread
        ( some, more -> thing)
        as being some with an additional more -> thing . Comma separates a lot. Comma space much more.

        Beside that, leading or trailing type doesn’t matter, when the separator is the space, like in Java/C or Google’s Go:
        (name type, name type) vs. (type name, type name)

        I always have to look at the position to decide what a word semantically is. parameter or type ?
        The colon (or the arrow btw) clearly display a tag for what’s coming. These are markups that I immediately look for when searching the type in an expression.

        So, as I separate by comma, it is easier to find the name always as first thing in the snippet:
        (name type, name more<complex<type&gt:>)

        fun Int max(Collection col, Fn<Int, Int: Int> compare)

        is horrible. My eye at a glance separates:
        Collection col
        followed by
        Fn<Int
        followed by
        Int:Int>
        followed by
        eventually the name of the parameter.

        (BTW: You see that I do not feel a strong bracing of < and >, why I prefer Scala’s square brackets over Java’s angle brackets too.)

    • Laurent mihalkovic says:

      So much emphasis is placed on the technical aspect of all these new languages that it often sounds like there is little time left to look at the code from 2ft away, to see how the most obvious parser will process it. Call me old fashion but, whatever a grammar says, if the brain reads something else, I would not bet the house on the long term chances of that language.

      If we were anywhere else but in the software industry, the answer would be obvious… run a blind test. But instead we are in the software industry where the few never even question that they would have all the answers for the many. Kotlin has some really appealing features… make it intuitive for switchers to embrace it and the sky is the limit…

    • Justin Malcolm says:

      I so much agree.

      Return types at the end and the resulting colon clutter are the two things I immediately dislike about Kotlin. If it was not for that, I am sure this language would be adopted like wildfire.

  13. Guangyu says:

    It’s great. I can’t wait to use it. Does it support OSGi?

  14. Sophie says:

    It is likely too late for this suggestion, even if it would otherwise be considered. But anyway …

    Please consider offering naming arguments at each call site, rather than exclusively positional arguments. Positional would (of course) still be available as before.

    Smalltalk syntax version of call site (call site readability far more important than any other :-)

    smartCar goTo: aLocation via: someViaPoints by: aDeadline

    There are several options to retain interoperability with Java, such as compiling to more than 1 method names (aliases). And with some modification (e.g. goTo instead of goTo: ) this can be considered a generalization of your optional-parenthesis for function call with 1 argument.

  15. B7W says:

    There are still a lot of colons. And in “Longer examples” it can be clearly seen.
    Generic:
    fun cloneWhenGreater<T : Comparable>(list : List, threshold : T) : List where T : Cloneable {

    Also inheritance is hard to read because constructor in class definition line. Maybe it is better to make default method, like python __init__.

  16. anonymous says:

    No! Now I have to throw my multithousnd lines fantasy-project over board.

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>