DSLs in Kotlin: Part 1. What’s in the toolbox + Builders

If you have a very nice API, it is the fashion nowadays to call it an internal DSL, because the code that uses such an API reads almost like a language inside your language of choice. Fluent interfaces serve as one of the most popular examples.

Many modern languages provide some advanced means for creating internal DSLs, and Kotlin is no exception here. In this post I will briefly list the features that are useful for this purpose.

Let’s start with extension functions. We all are familiar with Java’s utility classes, like java.util.Collections and like. Such classes are simply containers for a bunch of static methods, which are intended to be used with such and such classes. So we end up writing code like this:

and this does not look very pretty. Static imports make it prettier, but they don’t solve an important problem of discoverability: we all navigate through APIs with IDE’s code completion capability:
Code completion in IDEA
And wouldn’t it be cool to discover those utility functions the same way? So we have extension functions that are called in the form “a.foo()” even if foo() is not a member of the class of a. For example, those utility functions from Collections could be defined as extension functions, and be called like this:

These are still statically dispatched utility functions, i.e. the bytecode emitted by the compiler is the same as in Java, but the syntax is better, and code completion works. Note that, unlike members, extension functions cannot be overridden in subclasses, i.e. some special implementation of List could not override sort() to be more efficient.

To define an extension function, we just put a receiver type in front of its name:

Note that I can use a ‘this’ reference that represents my receiver object. See more here.

Now, what do extension functions give us, DSL creators? First of all you can turn any interface into a fluent one. For example, let’s create a new buffered reader with a given charset:

Is it a special class I wrote to be able to get this? No. It’s only two functions:

Then, they play very well together with operator overloading: in Kotlin, most operators, such as plus, minus and so on, are compiled by convention to named function calls. For example, when I say “a + b”, Kotlin reads “a.plus(b)” (see more in our docs). This means that by adding an extension function named “plus” to my type I can have a binary ‘+’ working on it. For example, I could make my own ‘+’ for list concatenation:

And call it like this:

And there’s more: since indexation is compiled to calls of get() and set() functions, we can have pretty sublists (or “slices”) that look like this:

By defining an extension function get() on a list:

Infix function calls add more on top of that, because you can say, for example

instead of

And, of course< you get a whole lot of fun with higher-order functions and function literals (i.e. “closures”). For example, check this out:

Is this a built-in construct, like Java’s synchronized section? No, it’s a function call. It uses a very handy convention: you can pass the last function literal outside the parentheses you put around your argument list. So this call is the same as “lock(myLock, {…})”, but looks prettier.

More about this example can be found here.

There’s one other nice convention that makes something very close to LINQ possible:

The convention is: If a function with only one parameter is expected, the parameter declaration may be omitted, and the default name ‘it’ will be used. I.e. “filter {it.foo()}” is the same as “filter {it => it.foo()}”.

And finally, if we put all this (and just a tiny little bit more) together, we can get something really nice. Look at this code:

Is it Groovy? No, it’s Kotlin, and, unlike Groovy, it’s statically typed. Yes, we can do builders like Groovy, but better. :) I added a detailed explanation of this example to our wiki; you can find it here.

Have a question? Opinion? Suggestion? We really appreciate your comments!

About Andrey Breslav

Andrey is the lead language designer of Kotlin at JetBrains.
This entry was posted in Language design and tagged . Bookmark the permalink.

26 Responses to DSLs in Kotlin: Part 1. What’s in the toolbox + Builders

  1. Very enjoyable post. Operator overload still scares me (C++ scars) but the rest is exciting. Give that Oracle just announced that Java 8 would be “revolution not evolution” I wonder how much they’ll steal from Kotlin? ๐Ÿ˜‰

  2. Eugene says:

    “something very close to LINQ possible”
    Does this hint that Kotlin will somehow support reification of its code into something similar to .NET expression trees?

  3. MuppetGate says:

    Looks great so far, but I’m still not sure about the ‘fun’ keyword.

  4. Andreas says:

    In contrast to MuppetGate I *really* like the fun keyword. It’s short, meaningful and is a good reminder what a programmer should have while coding …

  5. Lucian says:

    The extension methods proposed for Java 8 seem to be virtual and not static. Is there a reason why Kotlin will have static extension functions? For example if A extends B, will A be able to override an extension function defined to operate on B (e.g. in order to make it more efficient)?

    • In the Java 8 proposal, we use the term “extension methods” (earlier โ€” “defender methods”) to denote default implementations of methods declared in interfaces. These methods can not be added to a type by a third party. The same functionality is built in Kotlin’s traits, and, naturally, such function are overridable in Kotlin.

      What Kotlin means by “extension functions” is different: everyone can define an extension function on any accessible type, without modifying the type declaration.
      This gives us nicer syntax, discoverability by code completion and all the nice extras that make Groovy-style builders possible in Kotlin. Defined this way, extension functions can not be dynamically dispatched in an efficient manner.

  6. matt says:

    Apologies this is off topic, but I am very curious if there are any plans or thoughts to allow Kotlin to be cross-compiled to javascript and used in the browser. Or is it only for the JVM?

    • Yes, we are planning to compile Kotlin to JS. We haven’t started working on this yet, but this idea seems really appealing.

      • matt says:

        Thanks this is good to know. I hope can be something lightweight that interoperates well with existing javascript libraries, rather than being something huge like GWT which brings in lots of ports of jvm libraries.

  7. Otto Christian says:

    Looks fun, the support for LINQ-like queries and builders for HTML code makes me think that I would really like to develop web-apps in Kotlin. Has anyone started thinking about what a web framework in Kotlin would look like? How would it look similar or different from other popular frameworks like Grails, Play, Spring MVC, or Lift? I thnk there might be less of a need for a framework since the language itself does so much, but you probably still need something.

  8. Steve says:

    I don’t want to sound negative, but the blog post could have been abbreviated with “we try to do it pretty much like Scala, but with the following minor syntactic changes: … “.

    I still don’t see how JetBrains wants to be successful with Kotlin, considering that “the other language out there” delivers pretty much everything planned for Kotlin since almost a decade already.

    I just hope the resource drain of pushing Kotlin doesn’t kill the whole company, because the IDEs are pretty great.

  9. Vitaliy says:

    Will it be possible to compile kotlin code to java source instead of java bytecode? It will allow to use kotlin with GWT or any other source based compiler.

    • We don’t plan anything like this, although you can write such a back-end as soon as we open source the project.
      Warning: the generated Java code will be ugly, fragile and sometimes inefficient. Some features are impossible to implement this way without tricks like name mangling.

  10. Pingback: Building APIs on the JVM Using Kotlin and Spark - Part 1 | Nordic APIs |

Comments are closed.