ki: The Next Interactive Shell for Kotlin

ki: The Next Interactive Shell for Kotlin

There are several options to run Kotlin interactively:

kotlinc

and Kotlin REPL (read-evaluate-print loop) in IntelliJ IDEA.

Neither is ideal.

kotlinc

does not have autocomplete or syntax highlighting. Kotlin REPL is very powerful, but it forces you to open IntelliJ IDEA, which is not always convenient.

Allow me to introduce you to

ki

, a Kotlin Interactive Shell, and describe its benefits below.

And its main features are:

Download ki

Autocompletion

I like doing quick experiments with collections to find out what they have, what they do, and how I can obtain the desired result. The Kotlin collection API is huge, and it’s not humanly possible to remember everything it contains. Before

ki

, you had to go through the documentation a lot while working with kotlinc. This is a thing of the past with

ki

, as there is autocompletion to help! Here’s a quick example of how easy it is to write code in

ki

with the help of autocompletion.

One more thing to notice is that

ki

highlights the code, so it will be easier for me to read the code I wrote several inputs ago.

The nice thing we’ve kept from the original REPL in kotlinc is: every intermediate result is being written into variables named

res0

,

res1

, and so on. Each command is stored independently, which ensures I’ll be able to find any previous commands and reuse them.

Loading external dependencies

However, sometimes my experiments are a bit more complex than testing a random snippet. I may need to use a library, or write a throw-away one-liner using a 3rd-party library. For example, I like to use the Fuel HTTP client for HTTP interaction because it has an intuitive API.

ki

has the

:dependsOn

construct for this particular scenario. It allows me to add a library from Maven Central to my classpath.

To illustrate this, let’s try to determine which HTTP headers the

jetbrains.com

site sets when we’re visiting it.

No cookies – I love it already! But what is this mysterious

component2

I used? Let’s find out.

Type inference

If I did not remember what

component2

was, I could use the built-in

:t

command. It shows us that

component2

is of type Response and the

response

method returns

ResponseResultOf<ByteArray>

, which is an alias of

Triple<Request, Response, Result<ByteArray, FuelError>>.

Paste mode

Every now and then, I may want to insert a whole code snippet into my REPL, say, from Stack Overflow. How can I do that? I just need to type the

:paste

command to enter paste mode, like so:

Notice that the

ki

syntax highlights pasted elements, too. If I want to define a function myself, I can do it without paste mode. Syntax highlighting works the same for pasted code and code written right in the command-line.

Scripting support

What if I don’t want to import and add all the dependencies I need every time I launch

ki

? I can write a Kotlin script and load it into the shell! In the examples we’ve seen so far, almost everything can be expressed as a script:

@file:DependsOn("com.GitHub.kittinunf.fuel:fuel:2.3.1")
import com.GitHub.kittinunf.fuel.*
import java.net.*

fun sendGet(address: String) {
    val url = URL(address)

    with(url.openConnection() as HttpURLConnection) {
        requestMethod = "GET"  // optional default is GET

        println("Sent GET request to URL : $url; Response Code : $responseCode")

        inputStream.bufferedReader().use {
            it.lines().limit(5).forEach { line ->
                println(line)
            }
        }
    }
}

I can run the

:l

command, and both my imports and

sendGet

function are accessible.

Take a look at how I’m invoking the

:ls

command to find which functions were defined by the script I’ve just loaded. In this case, it’s only the

sendGet

function, but obviously, there may be much more content: functions, classes, variables, and so on.

Please note that

ki

does not support the execution of commands, which means we should replace the

:dependsOn

command with an

@file:DependsOn

annotation, which is explicitly created for scripting in Kotlin.

Plugins

Built with extensibility in mind,

ki

exposes the Plugin class, which lets developers extend the functionality of the shell. Like

:l

and

:ls

, all the commands mentioned above are implemented as plugins. The plugin class is self-descriptive and straightforward. Good examples of implemented plugins include the Paste Plugin and the Help Plugin.

One plugin that does not come included with the distribution is the Kotlin API for the Apache Spark plugin, just because there are not a lot of users for it.

ki

for Apache Spark

We’ve created a separate shell for Kotlin API for Apache Spark Users that bundles

ki

. There are two versions of the shell: one for Apache Spark 2.4 and another for Apache Spark 3. They both work with your local installation of Apache Spark and don’t require any additional dependencies.

Upon startup, the shell initializes Apache Spark, and on first execution, it creates a local Spark context. Starting with the second execution, queries work much faster because they reuse the existing context that’s already started.

There is a

spark

variable implicitly defined to work with Spark and to call the Kotlin API’s specific methods, like

toDS()

. You can see an example of

ki

for Apache Spark working below.

Everything else works like it does in regular

ki

.
Give it a try!
If you like what you’ve just seen, please try it for yourself!
Download ki
Download ki for Apache Spark
Github

Let us know what you think in the comments below or on Twitter.