20 November 2016

Kotlin Scripting


Many people won't be aware that Kotlin has scripting support, which includes the REPL. If you run the Kotlin compiler without any arguments you end up in the REPL (Read Evaluate Print Loop) environment, which is similar to Python's.

Kotlin REPL

Within the REPL basic expressions can be executed. Can even do block declarations. Some of the BASH keyboard shortcuts work, like Reverse Search (Ctrl + r) which will bring up the last line of code that was entered if it matches the search terms entered. As is the case with Python the order of code execution is from top to bottom. Currently documentation on Kotlin scripting is very scarce. The best place to look is on the Gradle website.

Kotlin REPL running code

Compilation time with each line of code that is executed is very FAST. So fast that there will be some situations where it is significantly quicker to try things (eg prototyping) out in the REPL rather than writing and executing a basic Kotlin program in a IDE. There is a file format called kts that represents a Kotlin Script which can be run in the REPL via the :load command. Can also run kts files using the Kotlin Compiler. Do note that the :load command does not accept a path to the kts file which contains spaces. Hopefully that will be fixed in a future Kotlin release.

For a more advanced/functional Kotlin REPL use the one provided by IntelliJ (is available in the open source Community edition). Despite being slower and not as stable as the original it does make it much easier to execute/manipulate blocks of code, and provides code completion as well as pop-up API documentation. Also all code is highlighted depending on the syntax highlighter that is used.

Kotlin REPL in IntelliJ

Kotlin REPL in IntelliJ - Running code

Be aware that you may encounter the infamous IDE lock-up bug where you do some code completion, and the IDE doesn't respond to keyboard and mouse events. Should such a situation occur then the IDE will need to be force closed and restarted. Not sure if the bug is fixed in the current IntelliJ Kotlin plug-in but be on the lookout just in case.

IntelliJ doesn't have a template for creating a Kotlin Script project so you will have to improvise by doing the following in IntelliJ:

  1. Goto FileNewProject…
  2. On left side select Empty Project
  3. Click Next button
  4. Enter in the project's name and location
  5. Click Finish button
  6. Goto FileNewModule…
  7. On left side select Kotlin
  8. On right side select Kotlin (JVM)
  9. Click Next button
  10. Enter in Kotlin for the module name
  11. Click Finish button
  12. Create a folder called src


A big advantage with the improvised Kotlin Script project is that you will have a clean REPL environment that only includes the Kotlin default imports by default. Also you have a central place to manage Kotlin Scripts should you want to keep existing code snippets to run in the future. Do note that kts files in the project cannot be accessed in the REPL (includes items like classes, variables, constants etc).

In an ordinary Kotlin project the REPL can access items (classes, variables, constants etc) from a kt file provided the source file is pre-compiled and is in a package. You will need to be careful when importing an item to avoid name-space clashes, especially at the top level.

Kotlin REPL in IntelliJ - Accessing module item

One last thing to mention is that Kotlin can be used for scripting at the terminal level via the kscript project. Below is a sample script from the project:

--------------------------------------------------------------------------------------------------
#!/usr/bin/env kscript
//DEPS com.offbytwo:docopt:0.6.0.20150202,log4j:log4j:1.2.14

import org.docopt.Docopt
import java.util.*


val usage = """
Use this cool tool to do cool stuff
Usage: cooltool.kts [options]  ...

Options:
 --gtf      Custom gtf file instead of igenome bundled copy
 --pc-only           Use protein coding genes only for mapping and quantification
"""

val doArgs = Docopt(usage).parse(args.toList())

println("Hello from Kotlin!")
println("Parsed script arguments are: \n" + doArgs.joinToString())
--------------------------------------------------------------------------------------------------