linkedin tracking
icon-sprite Created with Sketch.
Skip to main content

Mobile & Web


Kotlin/Native: Naughty or Nice?

Introducing Kotlin/Native

Kotlin/Native is an interesting new product from JetBrains that allows developers to code native applications for Linux, MacOS, Windows, and other platforms using the Kotlin language. This is potentially a big deal. Kotlin’s profile is rising rapidly. But until now, it has been mostly associated with the JVM and JavaScript. With Kotlin/Native, you’ll be able to write stand-alone apps that run natively. This will be especially useful in applications where virtual machines are not an option, like embedded applications. And along with the Kotlin multi-platform framework for mobile apps, it is a big step towards JetBrain’s goal of making Kotlin available for every environment. It is currently available in beta and is, JetBrains says, “feature complete”. That doesn’t mean that all expected features are there; instead, it means JetBrains has completed all of the features they intend to complete before initial release. So now is a great time to take a look at it. We’ll start with an overview of the Kotlin/Native tool chain, create a simple “Hello World” app, and then discuss a more substantial port from Kotlin to Kotlin/Native.

Compiling Kotlin Natively

Instead of writing a whole new set of compilers for Kotlin, JetBrains decided to leverage an existing toolchain, LLVM. If you aren’t familiar with LLVM, it’s a set of compiler tools created almost 20 years ago. You may have heard about it as part of Apple’s macOS and iOS development environments. Kotlin/Native compiles Kotlin code down to LLVM’s “intermediate representation”(IR), a low-level platform-independent language that LLVM understands. From there, LLVM compiles the IR down to executable code for the target platform.

Flowchart of Kotlin to Native Compiling

Your First Kotlin/Native Project

You may have heard that it’s hard to use Kotlin/Native. You may have heard that you need to use command-line tools and an unfamiliar IDE. Well, now you can forget all that! In 2018, JetBrains, the creator of Kotlin, made its IDE, IntelliJ IDEA, fully compatible with Kotlin/Native. Now, creating a Kotlin/Native project is easy.

To prove it, let’s walk through the steps to create your first Kotlin/Native application.

1) Open the IntelliJ IDE and click on “Create New Project”. For this example, I used a completely standard installation of IntelliJ IDEA Community Edition.

Welcome to IntelliJ page screen capture

2) Select “Kotlin” on the left hand panel and “Kotlin/Native” from the right hand panel. Click “Next”.

Kotlin new project window screen capture

3) Follow the rest of the wizard steps like any other new project. Once IntelliJ has created your new project, you should have a “Hello World” app that looks something like this:

IntelliJ new project window with “Hello World” app screen shot

Congratulations, you are now a Kotlin/Native developer. Easy, right?

Beyond “Hello World”

That’s a nice, painless introduction to your first Kotlin/Native project, but it’s only a “Hello World” console application. Is it actually possible to write more complex native applications using Kotlin? To find out, I decided to port a little 2D space shooter game, written in Kotlin for the JVM, to Kotlin/Native. It’s called Meteoroids and, in its original form, it looks like this (the project is available on GitHub):

Video game spaceship on left shooting at burning asteroids on right with starry space in background

If Kotlin/Native works as advertised, then I should be able to simply copy and paste the Kotlin code into the Kotlin/Native application with no modifications. The graphics in the game are based on a few Java classes. To replace them, I planned to use one of the popular Kotlin UI frameworks. The result looked like this:

UI framework for Meteoroids video game

As far as the Kotlin code is concerned, this port really was a copy and paste: the game mechanics work exactly the same as in the original with no modifications. But there was a big problem. Remember when I said that 'feature complete' doesn't mean that all the expected features are available? Two of those features are graphics and GUI support in Kotlin. There are some platform-specific options available - but no true cross-platform Kotlin GUI. Without those capabilities, I had to make some compromises. I decided to replace all the UI code with a character-based user interface instead. The result (also available on GitHub) looks a little different. But if you look closely, you'll see that it's exactly the same game. Granted, that’s a big compromise, and I wouldn’t blame you if you stopped reading right now and forgot about Kotlin/Native.

But if you’re willing to go beyond your JVM comfort zone, JetBrains provides a workaround which is worth investigating in its own right. Let’s look at how I got that text interface to work.

Interoperability With Common C Libraries

When writing Kotlin code for the JVM, you often make calls to libraries written in Java. JetBrains has now made Kotlin/Native similarly interoperable with a number of common libraries written in C. To demonstrate what this means, I will perform a little magic trick.

Kotlin project window screen capture with getpid code

What just happened? I called a function named getpid, which returns the ID of the currently running process. It comes from a standard C library named POSIX, which provides many system functions. But I called it from my Kotlin code, as if it was Kotlin itself. And it worked! Why?

Take a look at the line import platform.posix.getpid. This import allows us to use the POSIX getpid function as if it were written in Kotlin. But how does Kotlin/Native know about POSIX in the first place? To find out, look under “External Libraries” in the IDE. You will see a list of native libraries that are supported in Kotlin/Native as if they were Kotlin, and towards the bottom of the list, you will see POSIX.

long list of external libraries files screen capture

This is a bigger deal than it may seem at first. Kotlin/Native gives you access to a rich ecosystem of C libraries, which you can use as if they were Kotlin. Even if you don’t feel Kotlin/Native is ready for developing production apps, I recommend that you try this feature. It is pretty amazing and nearly seamless.

One big caveat is that the list of supported libraries varies according to the platform you’re developing on. Kotlin/Native currently leans very heavily towards the MacOS platform, so the list of libraries available on the Mac is extensive. You will see standard C libraries like POSIX as well as platform-specific libraries like MacOS’s AppKit. If you are developing an application for Linux, on the other hand, the list of available libraries is surprisingly limited.

much shorter list of external libraries files in Linux screen capture

I encountered this limitation when I tried to compile my space shooter game for Linux. The alternate UI I used is called ncurses, which provides a very simple character-based UI and has, I found, almost no learning curve. To make it work for my game, I only needed to change some of the sizing parameters (to account for a 100-character-wide text window instead of an 1800-pixel-wide graphical window) and replace the PNG images with ASCII images. That worked great on my Mac. But when I tried to compile the game for a Linux machine, it failed. It turned out that ncurses is not supported for Kotlin/Native on Linux. The library itself is available and widely used on that platform; it just hasn’t yet been added to Kotlin/Native by JetBrains.

This was a huge disappointment. But there is a workaround: you can add additional C libraries to your Kotlin application — even libraries that you write yourself. If you want to try that, be aware that, as of this writing, the official JetBrains documentation for adding libraries is a bit out of date. Instead, I recommend the Learn Kotlin Native website. After many hours of frustration with the official documentation, I followed the website author’s instructions and successfully added new libraries to my application.

One More Caveat: Memory Management

I realize memory management is the last thing a JVM programmer wants to think about, but if you use Kotlin/Native, you’ll need to be aware of how you manage your memory. As long as you are writing pure Kotlin code, Kotlin/Native will handle garbage collection for you. But whenever you use a function from a C library, you’re on your own.

Fortunately, JetBrains provides a new function to help: memScoped. As the name implies, all of the memory within a defined scope will be handled automatically. You can use memScoped for a block of code or an entire function. For a block, you code it in the form memScoped {...}. Any memory allocated within the curly braces will be automatically freed upon leaving the scope. It’s a pretty painless introduction to memory management for programmers accustomed to automatic garbage collection.

Conclusion

Is Kotlin/Native ready for prime time? The answer is no, it isn’t. Unless JetBrains implements things like a Kotlin-based, platform-independent GUI, it’s little more than a toy. But if you’re willing to expand your horizons into the world of C programming, you will find it gives you access to a rich ecosystem of libraries that are worth exploring in their own right.

Sign up for our newsletter


Delivered monthly, featuring great content from our blog!