Channels ▼
RSS

JVM Languages

Language of the Month: Kotlin


Kotlin is the name of a new statically typed programming language targeting JVM and JavaScript. Started in 2010 by JetBrains, the company behind numerous popular development tools such as IntelliJ IDEA and ReSharper, the Kotlin project is now available as open source.

Kotlin is a general-purpose language intended for industrial use. In particular, JetBrains plans to use it in the production of IntelliJ IDEA and other projects. The core motivation behind this project is the obvious need for a modern language for JVM. This need is evidenced by the fact that many developers and organizations are looking for an alternative to Java. Three new JVM languages backed by well-known industry leaders were announced during the last year, which suggests that many people are not satisfied with the existing alternatives.

Our goal with Kotlin is to create a language that is 100% Java-compatible, safer than Java, more concise and more flexible, and not overly complex.

Another important consideration is keeping compilation speed and IDE support on a level comparable to those in Java. These last two points may seem like insignificant technicalities, but our experience has shown that they do impose certain constraints on the language design.

While the compiler, IDE, and the language itself are under development, it is already possible to try many things out (with an IDE plugin or a lightweight online editor) and see what it is like to code in Kotlin. (The related Kotlin video shows coding using the IntelliJ IDE.)

This article gives an overview of Kotlin for Java developers and focuses on the interoperability between Java and Kotlin.

Hello, World!

Let's start with a "Hello, world" example. Unlike Java, Kotlin does not require us to define functions inside classes, so we can just declare a "free" function in a package:

package hello

fun main(args : Array<String>) {
  println("Hello, world!")
}

The syntax is more or less self-explanatory: The fun keyword denotes a function, Array is a generic class, and println() is a free function defined in the std package, which is imported by default.

Now, let's make it more object-oriented and personalized. Traditionally, this starts with defining a Greeter class:

class Greeter(name : String) {
  private val message = "Hello, $name!"
  fun greet() {
    println(message)
  }
}

Our class has a primary constructor that takes a parameter of type String. It is defined right in the class header, which saves us some lines of code compared with Java. In the class body, there is a private, read-only property message. It's defined with val stands for "value" and represents an immutable piece of state.

Primary constructors and vals should look familiar to Scala users, as should types following a colon. Another feature should be familiar to Groovy users: The message property is initialized with a string template. The $name template variable is replaced by the value of the name parameter passed to the constructor. The type of message is inferred to be String. As can be seen, Kotlin borrows features and ideas from other languages as well as adding original features of its own. The borrowing of features enables parts of the language to look familiar while allowing Kotlin to leverage the advances in programming language design.

Now, let's use our class to greet the user who passed a name on the command line (or the whole world, if no argument is provided):

fun main(args : Array<String>) {
  val name = if (args.isEmpty()) "world" else args[0]
  Greeter(name).greet()
}

You can see that val is used for a local value, too, and that if can be used as an expression. Also note that to create an instance of the Greeter class, we simply write Greeter(name). 


In other words, Kotlin doesn't have a new keyword.

Java Interoperability

A primary goal for Kotlin is to make the Java platform a better place to work, so that developers who choose Kotlin have all the benefits of Java, plus more. Thus, one of the absolute requirements for Kotlin is two-way interoperability with Java:

  • Java code can call Kotlin code,
  • Kotlin code can call Java code, and even make some of the APIs better.

This is the approach Scala and Groovy took, and we also think it is a must to make a JVM language an effective tool.

At JetBrains, we intend to use Kotlin to develop our main products such as IntelliJ IDEA. Of course, rewriting a whole codebase of more than 50,000 classes is not an option. Our strategy is to mix Java and Kotlin in the same code base, so that we can write new product features using Kotlin while gradually migrating old ones.

Compiling Mixed Projects

There are different issues in mixed projects: Kotlin must understand both Java sources and binaries and Java must understand Kotlin sources and binaries. While binaries are relatively easy (they are normal *.class files in both cases) mixing sources code is trickier: It's not difficult to imagine that a Kotlin compiler understands Java sources (although that looks like a lot of work), but making javac understand Kotlin sources is clearly impossible.

People take different approaches to solving this problem. For example, in Groovy, groovyc generates stubs from Groovy code — that is, Java source files containing only declarations of Groovy classes, methods, and fields — then runs javac on the stubs and Java sources. That way everything compiles, but Groovy classes don't have method bodies. Then it runs the real Groovy compiler to replace the stub classes with real ones. Thus, Groovy only looks at *.class files generated by javac and never tries to parse Java code. This comes at the expense of having the extra step for stub generation, which complicates the build process and takes time.

Another approach, used by Scala and Kotlin, is to teach our compiler to understand Java sources. In this case, it's enough to run kotlinc on the mixed source base, have it emit the *.class files for Kotlin classes, and then run javac against the java sources and Kotlin binaries. Fortunately for us, it's very easy to implement a Java parser and do further analysis because IntelliJ IDEA is very good at it already, so all we need is just to reuse the relevant parts.

The only thing left is to make the IDE itself understand mixed projects, so that we can navigate from Kotlin code to Java and back. And again, only the reverse part is hard: we can't afford generating *.class files every time we want to navigate from a Java class to Kotlin. Or can we?

Actually, the IDE invokes a lightweight version of code generation that writes nothing to disk and skips method bodies (very much like Groovy stubs, but no compiler relies on them) and builds a Java model of Kotlin classes in memory to facilitate name resolution in the IDE.

Making Java APIs Better

As mentioned previously, Kotlin can do better than merely reuse Java libraries: It can enhance them. The main way to do this is through extension functions and properties. This feature should be familiar to Groovy and C# users. (Scala achieves a similar effect with a different technique: implicit conversions.) Let's start with a simple example and add an isNotEmpty() function to the String class. (I'd use isEmpty(), but the JDK guys finally figured that this method is useful and added it to JDK 6.) To do this addition, we define an extension function for String:

fun String.isNotEmpty() = ! this.isEmpty()

The String. prefix to the function name tells us that this function should be called on references of type String, like this:

if (name.isNotEmpty()) {
  println("Hello, $name!")
}

In the body of the function we can refer to that string using this, as if our function were a member of the String class. So, with extension functions we can add capabilities to classes that are in our control, thus enriching their APIs.

An important note: Extension functions are not real members of classes; they are statically bound, that is they're not virtual. Technically, they are very much like good old Java utilities found in java.util.Collections or java.util.Arrays, only in a different syntactic form. ,p>Do we really need them? If no magic happens, is the syntactic sugar worth it? We think it is, but there are some important additional reasons.

Take the process of learning a new API. How do we all do it? Starting with a manual? Not really: We type a dot in the IDE and press a key sequence to review the completion options that tell us in a pop-up window what we can do with this object. We fall back on the manual (or Google) when the thing we are looking for is hidden in some utility class. So, extensions add one important thing: discoverability by code completion. The IDE suggests available extensions as if they were normal members, which makes learning APIs easier.

Convention-Based Language Constructs

Another good thing about extensions is that Kotlin treats many syntactic constructs by convention. The for loop is a good example: Unlike Java, which requires an Iterable in the enhanced for loop, Kotlin is fine with any class that has an iterator() function, even an extension function. This is very much like duck typing. Now, if I want to iterate through a String in Kotlin, all I have to do is define an extension:

fun String.iterator() = StringIterator(this)

We assume that the StringIterator class is defined in an obvious way. Now, the for loop works fine:

fun String.isNumber() : Boolean {
  for (c in this) {
    if (c !in ‘0'..'9') return false
  }
  return true
}

This is again an extension function, so that we can type, for example, input.isNumber().

Another feature that works by convention is operator overloading. In Kotlin, things like '+,' ‘-,' ‘in,' and so on are nothing but shorthand for function calls (optimized for built-in types such as Int). For example, a + b stands for a.plus(b) and works whenever there is an appropriate plus function defined for a. This means that if we want, say, to use BigInteger in a natural way — that is, as a number — we can define the corresponding extensions. For example:

fun BigInteger.plus(other: BigInteger) = this.add(other).sure() 

This function enables the following code:

fun sum(data : List<BigInteger>) : BigInteger {
  var sum = "0".toBigInteger() // another extension for String
  for (x in data)
    sum = sum + x
  return sum
}

Other operators can be added in a similar manner.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video