Intro

In case you don’t know, Kotlin is a programming language which started as a replacement for Java, but better. We can use it to build applications for the JVM, but with the latest additions we can do so much more.

Kotlin everywhere

If at first we could use Kotlin wherever Java was available, now we can use it almost everywhere.

We can create backend and Android applications using Kotlin/JVM.

We can create web applications using Kotlin/JS.

And we can even create iOS applications or desktop applications (Windows, Linux, macOS) using Kotlin/Native.

Disclaimer: As Kotlin/JVM is available already for a long time, in this article we will focus more on the other platforms.

Kotlin/JS

How does it work ? We write the code in Kotlin (.kt files). These files will pe parsed by kotlinc (the Kotlin compiler) and will be transpiled to Javascript. This works in the same way as other Javascript transpilers work (like Typescript).

A tool that helps us developing these kind of applications is ts2kt. In the Javascript world, we use .d.ts files which are type definition files. They are used by the IDE for features like autocomplete. Popular libraries already come with these files, and the ts2kt tool generates metadata from these files so we can have autocomplete and type definitions in Kotlin as well.

Javascript does not have types, so what can we do when we do not know the type of a variable ?

We can use the dynamic type in such situations. This type, only available in Kotlin/JS, lets us access any field on the variable without any kind of safety.

val response: dynamic = loadJson("example.com/api") val text = response.items[0].title

We just have to make sure that at runtime those fields will exist. The block of code with dynamic variables will be transpiled to Javascript just as it is, like a copy-paste.

As it turns off type-checking and compile-time safety, we should use it only when it is absolutely necessary.

React support ?

As we can use any Javascript library in Kotlin/JS, you may think it would be really cool if we can write React applications in Kotlin, and we can. JetBrains even created a library of Kotlin wrappers for the classes in React. We can use this library to write React applications in Kotlin even easier.

There is also a CLI tool called create-react-kotlin-app which we can use to create boilerplate for a new app in Kotlin with React.

https://github.com/jetbrains/kotlin-wrappers

https://github.com/JetBrains/create-react-kotlin-app

kotlin-frontend-plugin

For web frontend applications we can use kotlin-frontend-plugin. This is a Gradle plugin which helps us easily configure common things like npm libraries or webpack properties.

Example for adding npm libraries:

kotlinFrontend { npm { dependency "style-loader" // production dependency devDependency "karma" // development dependency } }

Example for Webpack configuration:

kotlinFrontend { webpackBundle { bundleName = "main" // output bundle name sourceMapEnabled = true // enable source maps host = "localhost" // set host name port = 8088 // set port } }

Multiplatform projects

This feature allows us to easily write platform specific implementations.

Important: this is not a write-once-run-everywhere solution.

We can declare the contract of a class in a common module, and in platform specific modules provide the actual platform-dependent implementation.

Using the expect keyword we can mark that the implementation of a class comes from somewhere else.

Using the actual keyword we can provide the implementation.

The binding between these two is done by using the same package name.

Note: Maybe you noticed that in the example image above, on the Javascript platform we do not implement the getFullYear() method, and we use the external keyword for the class. This is because we already have the Date class in Javascript, so we do not need to implement it, as it will be provided by the Javascript engine.

Why not interfaces ? I think using expect/actual is easier and more flexible and we do not need to complicate things with other solutions like dependency injection.

How to create platform specific modules ?

To create a common or platform modules we use the kotlin-platform-common, kotlin-platform-jvm or kotlin-platform-js Gradle plugins (in the corresponding build.gradle file of the Gradle module):

Create a common module:

apply plugin: 'kotlin-platform-common' dependencies { // here we can add common libraries as dependency compile "org.jetbrains.kotlin:kotlin-stdlib-common:$version" }

Similar for JVM:

apply plugin: 'kotlin-platform-jvm' dependencies { // here we can add JVM libraries as dependency compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$version" expectedBy project(":app-common") }

Similar for Javascript:

apply plugin: 'kotlin-platform-js' dependencies { // here we can add Javascript libraries as dependency compile "org.jetbrains.kotlin:kotlin-stdlib-js:$version" expectedBy project(":app-common") }

Maybe you noticed the expectedBy keyword. This keyword create a link between the common module and the platform specific module.

Common libraries helps us to not implement different functionalities every time.

What common libraries are already ?

Kotlin Standard Library

kotlin.test (testing library)

kotlinx.html (easily create HTML pages using Kotlin)

kotlinx.serialization (helps us do serialization, it supports: JSON and ProtoBuf but can be extended for custom formats)

Kotlin/Native

It is a LLVM-based toolchain that compiles Kotlin code to native binaries.

It can be used to develop iOS apps but keep in mind that we still need macOS and Xcode that takes care of the packaging, signing and everything else for the app.

We can use existing Objective-C libraries for our project.

All of this is possible because of the cinterop tool. This tool generates Kotlin metadata from C header files. This way we can use C libraries as if they were written in Kotlin.

As we are talking about native, maybe you are wondering about stuff like memory management. Currently Kotlin/Native uses reference counting with a cycle collector and the memory is not shared between threads. However these things are very likely to change in the future.

The recommended IDE for developing Kotlin/Native applications is CLion. It has a Kotlin/Native plugin that helps us with features like autocomplete. It supports debugging our application and it also has support for the kotlin.test library, so we can run tests from the IDE.

Conclusion

Goal: write all parts of your application in the same language.

You can share the business logic of your app between multiple platforms.

The UI must be implemented separately for each platform.

Kotlin/JVM and Kotlin/JS are available, Kotlin/Native is still in alpha.

Demo

I also created a small application (platforms: Android, iOS and web). It displays the top 10 Kotlin repositories from GitHub.

If you are curious about the code you can find it here: https://github.com/radiKal07/KotlinGithubTop10

I hope you found this article informative.

Thanks for reading.