Kotlin for C++ Developers

Kotlin for C++ Developers

By Hadi Hariri

Overload, 25(139):16-17, June 2017


What could a language the originated on the JVM possibly offer C or C++ devs? Hadi Hariri tells us.

Kotlin is a programming language that was initiated by JetBrains, makers of developer tools such as IntelliJ IDEA, CLion, ReSharper et al. It started in 2010 as a need for JetBrains to use a language that was less verbose than Java, had ‘modern’ constructs, good tooling, and led to more maintainable code in the long run. After looking at the alternatives at the time, a decision was made to write their own.

Fast-forward to February 2017 and Kotlin released version 1.1 which targets not only the JVM but JavaScript. With an impressive growth in adoption since the release of the first version in February 2016, Kotlin is now being used by companies large and small, including Netflix, Gradle, American Express, Expedia, Pinterest, Trello, BBC, just to name a few.

In March 2017, JetBrains, we, announced the first Technology Preview of Kotlin/Native, which is Kotlin without any kind of virtual machine, targeting via LLVM multiple platforms, including

  • Mac OS X 10.10 and later (x86-64)
  • x86-64 Ubuntu Linux (14.04, 16.04 and later), other Linux flavours may work as well
  • Apple iOS (arm64), cross-compiled on macOS host
  • Raspberry Pi, cross-compiled on Linux host

Kotlin is a language that is designed to be used at industrial scale, targeting any type of application development, be it backend, desktop, front-end on the web as well as mobile. And of course, now with native, other possibilities come into play such as embedded and Internet of Things.

As a C or C++ developer though, what does Kotlin, and in particular Kotlin/Native, have to offer? To answer that, let’s take a brief look at some of the key features of the language.

Above all, pragmatism

The main principle behind Kotlin is pragmatism. While it is unfortunate that at times that word is used to justify shortcomings, in the case of Kotlin the purpose is to look at common situations we encounter as software developers when using different languages and solving problems, and try and address these.

To give some examples – in the business world we often use the concept of data transfer objects, a class that holds some properties but really doesn’t have much when it comes to behaviour. It does, however, require certain things such as the ability to represent the data as a string, to copy from one instance to another, or to compare two instances based on properties. In Kotlin, all this can be done in a single expressive line of code:

  data class Customer(val name: String,   val email: String, val country: String)

This line provides a class with three properties, that are read-only ( val indicates read-only, var indicates writable), namely: name , email and country . But in addition it provides a function toString , equals , copy , and hashCode .

Conciseness appears in other ways, following the principle of not repeating oneself, Kotlin doesn’t require explicit type declaration or conversion when the compiler can easily infer things. For instance, variables can be declared and initialised without explicitly declaring the type

  val myString = "Something"

as opposed to the longer format

  val myString : String = "Something"

When performing type conversions, there’s no need to verify and cast explicitly:

  If (myObject is Customer) {
                myObject.makeActive()

auto-casting takes place, as opposed to having to explicitly convert the type

  If (myObject is Customer) {
                (Customer)myObject.makeActive()

Certain patterns, such as the Singleton pattern become extremely easy to implement in Kotlin, as it has the concept of an object (a single instance, not requiring instantiation from any class)

object Global {
  val version = "0.1"
  fun log(message: String) {
    println("LOG: $message")
  }
}

fun usingSingletons() {
  Global.log("A Message is sent")
}

Of course Kotlin isn’t only about conciseness, but also provides a series of characteristics that allow for writing nice statically-typed DSLs. Being a language that treats functions as first class citizens, it allows for higher-order functions and lambda expressions

  val countryCapital = listOf("Madrid" to "Spain",
   "London" to "UK", "Berlin" to "Germany",
   "Washington DC" to "USA")
  val capitals = countryCapital.map {
    it.first
  }.sorted()

The combination of extension functions, which allow us to extend an existing type with new functionality without having to inherit from it, lambda expressions, and a series of other features and conventions allow us to create DSLs like the following:

  build {
    make {
      source = "*.kt"
      target  = "/tmp"
   }
  }

where each of the elements are actual static identifiers.

Leveraging the platform

A language alone in isolation often doesn’t provide the productivity someone needs. The focus on pragmatism in Kotlin also surfaces when we’re speaking about interoperability with platforms and leveraging existing libraries, frameworks and in general the ecosystem present. This is demonstrated on the JVM with interoperability with Java and JVM libraries, in JavaScript with interop with package managers, JavaScript standards and of course when it comes to native, Kotlin also provides interop with C.

The code in Listing 1 demonstrates how we can interact with C libraries, in this case provide socket functionality.

import kotlinx.cinterop.*
import sockets.*

fun main(args: Array<String>) {
  if (args.size < 1) {
    println("Usage: ./echo_server <port>")
    return
  }

  val port = atoi(args[0]).toShort()

  memScoped {
    val bufferLength = 100L
    val buffer = allocArray<ByteVar>(bufferLength)
    val serverAddr = alloc<sockaddr_in>()
    val listenFd = socket(AF_INET, SOCK_STREAM, 0)
        .ensureUnixCallResult { it >= 0 }

    with(serverAddr) {
      memset(this.ptr, 0, sockaddr_in.size)
      sin_family = AF_INET.narrow()
      sin_addr.s_addr = htons(0).toInt()
      sin_port = htons(port)
    }

    bind(listenFd, serverAddr.ptr.reinterpret(),
      sockaddr_in.size.toInt())
      .ensureUnixCallResult { it == 0 }

    listen(listenFd, 10)
      .ensureUnixCallResult { it == 0 }

    val commFd = accept(listenFd, null, null)
      .ensureUnixCallResult { it >= 0 }

    while (true) {
      val length = read(commFd, buffer,
        bufferLength)
        .ensureUnixCallResult { it >= 0 }
      if (length == 0L) {
        break
      }

      write(commFd, buffer, length)
         .ensureUnixCallResult { it >= 0 
    }
  }
}
			
Listing 1

Next steps

If you want to learn more about Kotlin, the best place to get started is with the Kotlin Koans, which are a series of exercises that can be performed online [ https://try.kotlinlang.org ] or offline [ https://kotlinlang.org/docs/tutorials/koans.html ]. Kotlin is completely open when it comes to tooling. You can use anything, be it the command line compiler, which is simple, up to a fully fledged IDE such as IntelliJ IDEA (works in both the free OSS Community Edition as well as the commercial Ultimate one). In addition to IntelliJ IDEA, at JetBrains we also provide support for Android Studio, Eclipse and Netbeans.

Summary

It is close to impossible to cover extensively any language in such a short amount of space. Independently of this fact, however, I’ve personally found that with Kotlin it is not about specific features that make it stand out, but how all these different things fit in together to provide a better experience when writing and reading code. And it is this experience that can now be shared across multiple platforms with different developers of different backgrounds. As a C or C++ developer, what Kotlin can provide is a higher-level language abstraction, making code often easier to write, and more importantly understand, while at the same time not losing the power to interact with low-level constructs when needed.

Kotlin/Native still has a long way to go, but this first technology preview itself is a big milestone. The focus for the Kotlin/Native team is to continue to build on what is currently available, improving tooling, providing support for more platforms and in general providing a pleasurable development experience to all.






Your Privacy

By clicking "Accept Non-Essential Cookies" you agree ACCU can store non-essential cookies on your device and disclose information in accordance with our Privacy Policy and Cookie Policy.

Current Setting: Non-Essential Cookies REJECTED


By clicking "Include Third Party Content" you agree ACCU can forward your IP address to third-party sites (such as YouTube) to enhance the information presented on this site, and that third-party sites may store cookies on your device.

Current Setting: Third Party Content EXCLUDED



Settings can be changed at any time from the Cookie Policy page.