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:
- External dependencies support
- Type inference support
- Special paste mode to paste large snippets found somewhere
- Scripting support
- Kotlin API for Apache Spark support
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
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.
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>>.
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.
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:
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.
Built with extensibility in mind,
ki exposes the Plugin class, which lets developers extend the functionality of the shell. Like
: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.
Let us know what you think in the comments below or on Twitter.