Tag: tutorial

Kotlin Tutorial – Quick Reference – Getting Started with Kotlin

Kotlin Tutorial – Quick Reference – Getting Started with Kotlin

Introduction

Disclaimer: This reference has originally been published as a DZone Refcard.

Kotlin has become one of the most popular JVM languages in the past few months. One special reason is that it experienced a lot of attention in the Android community after Google made Kotlin an official language for Android development. Kotlin is being developed by JetBrains, who are responsible for the most famous IDEs out there, most notably IntelliJ IDEA. Nevertheless, it’s an open source language, which can be found on GitHub.

The language is said to be very concise, safe in terms of error frequency, interoperable with Java and also offers many features that enable functional programming, writing type-safe DSLs and much more. Beside the JVM, Kotlin can compile for most Android versions, down to machine code using LLVM and can also be transpiled to JavaScript.
Kotlin has already been adopted in many popular frameworks and tools such as Spring and Gradle. It continues to gain traction in multiple domains, and there has never been a better time to get started with Kotlin.

Where to Start Coding

When you want to start writing your first Kotlin code there are quite a few ways to do that. Apparently, the recommended way is to work with IntelliJ IDEA, which offers the best support. As an alternative, one could also start with the command line or use JetBrains’ Kotlin web IDE to do some Kotlin Koans. Whichever way you prefer, corresponding tutorials can be found here: kotlinlang.org/docs/tutorials/.

Basic Syntax

Kotlin was inspired by many modern programming languages like C#, Groovy, Scala and also Java. Even more, Kotlin can be seen as an extension to the Java language, making it better by adding functionality to existing standard classes (e.g. String, List) and of course by providing great features, which are in large part enabled by applying compiler-supported techniques. As in Java, Kotlin programs are entered via a main method, such as the following:

fun main(args: Array): Unit {
    val inserted = "Kotlin"
    println("Let's get started with $inserted")
}

What we can see in this snippet is:

  • Functions are initiated by the keyword fun, followed by a name
  • Parameters and also variables in Kotlin are declared by defining a name and a type, both separated by a colon as you can see in args: Array
  • The return type of the main is Unit, also prefaced by a colon. In case of a Unit return, which corresponds to Java’s void, the compiler does not require you to explicitly define the return type, so the part : Unit could be omitted
  • Kotlin does not require you to use semicolons for separating statements (in most cases)
  • Type inference is supported in many situations as shown with val inserted, which also could be declared with an explicit type as val inserted: String
  • String templates can be used, which means that it’s possible to include variables and even expressions in Strings directly using $varname or ${statement} syntax
  • main is declared without a wrapping class around it. Functions and variables in Kotlin may be declared at “top-level”, i.e directly inside a package
  • No visibility modifier is used here. Functions, classes, variables etc. are public by default. When different visibility is needed, choose from:
KeywordEffect on Top-Level declarations [1]Effect on Class Members
publicvisible everywherevisible everywhere if class is accessible
privatevisible inside the file onlyvisible inside the class only
protectedvisible in class and subclasses
internalvisible inside the same module [2]visible in the same module, if class is accessible

1: Functions, properties and classes, objects and interfaces can be declared on the “top-level”
2: A module is a set of Kotlin files compiled together: an IntelliJ IDEA module, a Maven project, a Gradle source set

  • Variables defined as val cannot be re-assigned, i.e. are read-only. Alternatively, if mutability is inevitable, var can be utilized, as shown in the next example:
var mutableVar = StringBuilder("first")
mutableVar = StringBuilder("second")
  • Constructor is invoked without the new keyword, which is omitted from kotlin

Control Flow: Conditions

In Kotlin you can make use of if, when, for and while for controlling the behavior of your code. Let’s look at conditions first.

If-Statement

val min: Int
if (x < y) {
    min = x
} else {
    min = y
}

It’s important to know, that many statements in Kotlin can also be used as expressions, which for instance makes a ternary operator obsolete and apparently shortens the code in most cases:

val min = if (x < y) x else y 

When-Statement A when statement is very similar to switch operators and could, in theory, easily replace if-statements as they are much more powerful.

val y = when (x) { 
    0 -> "is zero"
    1 -> "is one"
    2, 3 -> "two or three"
    is Int -> "is Int"
    is Double -> "is Double"
    in 0..100 -> "between 0 and 100"
    else -> "else block"
}

In a when statement, which can also be used as an expression, all branches are tried to match the input until one condition is satisfied. If no branch matches, the else is executed. As shown in the snippet, when branch conditions can be values, types, ranges and more.

Control Flow: Loops

For-Loop

In Kotlin, there’s no conventional for-loop, as you know it from C or Java. Instead, foreach loops are the default.

for (c in "charSequence") {
    println(c)
}

In many cases, looping with an index is necessary, which can easily be achieved with the indices property that is defined for arrays, lists and also CharSequences for example.

for (i in "charSequence".indices) {
    println("charSequence"[i])
}

Another way of iterating with indices is possible by using withIndix().

for ((i,c) in "charSequence".withIndex()) {
    println("$i: $c")
}

Last but not least, Kotlin has ranges, which can also be utilized for indexed iterations as the following shows:

(0 .. "charSequence".length-1).forEach {
    print("charSequence"[it])
}

The range in this example is expressed with the common .. syntax. To create a range which does not include the end element (s.length), the until function is used: (0 until s.length).

While-Loop

Constructs with while or do-while loops are straight-forward, all works as known from other common languages.

Basic Types

In Kotlin everything looks like an object to the user, even primitive types. This means, member functions can be called on every type, although some will be represented as JVM primitives at runtime.

Numbers

The default number types are: Double, Float, Long, Int, Short, Byte
* Underscores can be used to make large numbers more readable: val million = 1_000_000
* Number types offer conversion methods like toByte(): Byte, toInt(): Int , toLong(): Long
* Characters are no number type in Kotlin

Chars

A Char represents characters and cannot be treated as a number.
* They are declared within single quotes, e.g. '42'
* An explicit conversion from a Char to an Int can be accomplished with the toInt() method

Booleans

Booleans can have the two common values true and false
* They can be operated on with: ||, &amp;&amp; and !

Strings

Strings are immutable sequences of characters.
* They offer an index operator [] for accessing characters at specified positions
* A string literal in Kotlin looks like "Hello World" or """Hello World with "another String" in it"""
* The latter is called raw string that can contain any character without needing to escape special symbols
* Strings in Kotlin may contain template expressions

Arrays

An array is represented by the class Array, which offers very useful methods to the client.
* Values can be obtained via get(index) or [index]
* Values can be set via set(index, value) or [index]=value
* Arrays are invariant, i.e. an Array cannot be assigned to a variable of type Array
* Special types for arrays of primitive types exist as IntArray or ShortArray for instance. Using those will reduce the boxing overhead.

Classes

A simple class can be declared like in this snippet:

class Person constructor(name: String) {}

The primary constructor is part of the class header, secondary constructors can be added in the class body. In the shown case, the constructor keyword could also be omitted, since it’s only mandatory if you want to add annotations or visibility modifiers (default: public).
Constructor parameters such as name can be used during the initialization of an object of this class. For this purpose, an init block would be necessary, because primary constructors can’t contain code directly. Constructor arguments can also be used in property initializers that are declared in the class body, as shown here.

class Person(name: String, age: Int) {
    init {
        println("new Person $name will be born.")
    }

    val ageProp = age
}

As mentioned, Kotlin classes can contain properties, which are accessed by simply calling obj.propertyName to get a property’s value and obj.propertyName = "newValue" to modify the value of a mutable (var) property. Declaring properties for classes can also be done in the primary constructor directly, which makes the code even more concise. Like in all methods, Kotlin supports default parameters for parameters, set with “=“.

class Person(val name: String, val age: Int = 50)

Same as with local variables, instead of val, a property can be declared mutable using var instead. Note that you don’t have to write an empty class body if no content is defined.

Special Classes

Besides ordinary classes, Kotlin knows a few special class declarations, which are worth knowing. The following will give a quick overview.

TypeExplanation
data classAdds standard functionality for toString, equals, hashCode etc.
sealed classRestricts class hierarchies to a set of subtypes. Useful with when
Nested classClasses can be created in other classes, also known as “inner class”
enum classCollect constants that can contain logic
object declarationsUsed to create Singletons of a type

Of course, Kotlin also supports inheritance through interfaces and abstract classes.

Function Types and Lambdas

In order to be able to understand idiomatic Kotlin code, it’s essential to recognize how function types and especially lambdas look like. Just as you can declare variables of type Int or String, it’s also possible to declare variables of function types, e.g. (String) -> Boolean.

val myFunction: (String) -> Boolean = { s -> s.length > 3 }
myFunction("HelloWorld")

The variable is declared as a function type that takes a String argument and returns a Boolean. The method itself is defined as a lambda enclosed in curly braces. In the shown lambda, the String parameter is declared and named before the -> symbol, whereas the body follows after it.

Lambda Special Syntax

The language designers decided on some special lambda features, which make the usage even more powerful.

  1. it: implicit name of single parameters

In many cases, lambdas are used with single parameters like in the previous example. In such situations, you don’t have to give the parameter an explicit name. Instead, the implicit name it can be used.

val myFunction: (String) -> Boolean = { it.length > 3 }
myFunction("HelloWorld")
  1. For unused parameters, use _

In some cases, it might be unnecessary to make use of every possible available parameter in a lambda. The compiler warns the developer about such unused variables, which can be avoided by naming it with an underscore.

val myFunction: (String, Int) -> Boolean = { s, _ -> s.length > 3 }
myFunction("HelloWorld", 42)

Higher-Order Functions

If a function takes another function as an argument or returns another function as its result, it’s called a higher-order function. Such functions are essential in Kotlin as many library functions rely on this concept. Let’s see an example.

fun main(args: Array) {
    myHigherOrderFun(2, { it.length > 2 })
}

fun myHigherOrderFun(iterations: Int, test: (String) -> Boolean){
    (0 until iterations).forEach {
        println("$it: ${test("myTestString")}")
    }
}

The function myHigherOrderFun defines two parameters, one of which is another function test. The function takes test and applies a String to it multiple times depending on what the first argument iterations is. By the way, the example uses a range to imitate an indexed for loop here.

The shown main function demonstrates the usage of a higher-order function by calling it with an anonymous function. The syntax looks a bit messy, which is why the language designers decided on a very important convention: If a lambda is the last argument to a function, it can be placed after the closing parentheses or, if it’s the only argument, the parentheses can be omitted completely like shown with forEach above. The following snippet demonstrates this convention applied to an invocation of myHigherOrderFun.

//Lambda after closing parentheses
myHigherOrderFun(2) {
    it.length>2
}

Top Features

There are some features in Kotlin, everybody should be familiar with. These are essential for many libraries, standard functions and also advanced features like Domain Specific Language support.

Null-Safety

The type system differentiates between nullable and non-null types. By default, a class like String cannot reference null, which raises the attention for null-related problems. As opposed to String, the type String? can hold null. This does not make a big difference on its own. Therefore, working with nullable types implies having to handle nullable values in a special way.

var b: String? = "couldBeNull"
b = null //okay

// 1. Access directly: does not compile, could throw NPE
// val len = b.length

//2. Use safe-operator
val len = b?.length

//3. Check nullability before accessing
if(b != null){
    b.length
}

It’s possible to check whether a variable is not null before accessing it. In such cases, the compiler permits the usage without special safety measures. Alternatively, b?.length expresses: call length on b if it’s not null, otherwise the expression returns null. The return is of type Int? because null may be returned. Chaining such calls is possible, which is very useful. Other operators used with nullable types are shown in the following overview.

OperatorUse caseExample
!!Ignore warnings of compiler and overcome null checks. Use cautiously only.x!!.length
?:The elvis operator is used to give an alternative for null results.val len: Int = b?.length ?: 0
as?A safe cast tries to cast a variable in a type and results in null if the cast is not possible.val i: Int? = s as? Int

Extensions

Another essential feature of Kotlin is extensions. An extension is used to extend a class with new functionality without having to inherit from that class. Extensions can have the form of properties and functions. The Kotlin standard library contains a lot of such extensions, like the following defined on String:

public fun String.substring(range: IntRange): String = 
    substring(range.start, range.endInclusive + 1)

//usage
"myString".substring(0..3)

In this example String is the receiver of the defined substring(range: IntRange) function. An extension function can use visible members of its receiver without additional qualifiers since this refers to the receiver. In the snippet, String‘s standard method substring(startIndex: Int, endIndex: Int) is called in that way. The extension is called on a String as if it was a regular method.

It’s also possible to extend a class with properties. For example, Int can be extended with a property that represents its version of BigDecimal. This might be useful if otherwise, the constructor of BigDecimal had to be used many times.

val Int.bd
    get() = BigDecimal(this)

val bd: BigDecimal = 5.bd

Extensions are mostly defined on top-level and can be used in other files after they have been imported explicitly.

Lambda with Receiver

Higher-order functions can be even more powerful if used with “lambdas with receiver”. It’s possible to call function literals with a specific receiver object, similar to the extension functions. As a result, members of the receiver can directly be accessed inside the lambda without having to use additional qualifiers. This feature is the foundation for Kotlin’s fantastic support for writing Type-Safe Builders, also known as Domain Specific Languages.

fun T.apply(block: T.() -> Unit): T {
    block()
    return this
}

This snippet shows a slightly simplified version of the apply function, which is part of Kotlin’s standard library. It’s an extension function on the generic type T, thus can be used with any object. The function takes a function literal with T as its receiver and executes the block before this (the receiver of apply) is being returned.

data class GuiContainer(
    var width: Int = 0,
    var height: Int = 0,
    var background: String = "red"
) {
    fun printMe() = println(this)
}

fun main(args: Array) {
    val container = GuiContainer().apply {
        width = 10
        height = 20
        background = "blueish"
        printMe()
    }
}

In this example, the data class GuiContainer is created with default parameters and then the apply method is called on it. It’s possible to set mutable properties and call methods of the receiver GuiContainer like shown with the invocation of printMe() in the end. Since apply returns the receiver after it completes, it can directly be assigned to a variable.

Idiomatic Kotlin

Kotlin tries to encourage particular coding idioms to be used. These are partially listed in the documentation and also in some community driven articles. The following will present some of these idioms by example.

  1. Use when as an expression if possible
fun analyzeType(obj: Any) =
        when(obj){
            is String -> "is String"
            else -> "no String"
        }
  1. Use elvis operator with throw and return to handle nullable values

class Person(val name: String?, val age: Int?) fun process(person: Person) { val pName = person.name ?: throw IllegalArgumentException("Name must be provided.") println("processing $pName") val pAge = person.age ?: return println("$pName is $pAge years old") }
  1. Make use of range checks
fun inLatinAlphabet(char: Char) = char in 'A'..'Z'
  1. Prefer default parameters to function overloads
fun greet(person: Person, printAge: Boolean = false) {
    println("Hello ${person.name}")
    if (printAge)
      println("${person.name} is ${person.age} years old")
}
  1. Use type aliases for function types
typealias StringPredicate = (String) -> Boolean

val pred: StringPredicate = {it.length > 3}
  1. Use data classes for multiple return values
data class Multi(val s: String, val i: Int)

fun foo() = Multi("one", 1)

fun main(args: Array){
    val (name, num) = foo()
}
  1. Prefer extension functions to utility-style functions
fun Person.greet(printAge: Boolean = false) {
    println("Hello $name")
    if (printAge)
        println("$name is $age years old")
}
  1. Use apply for object initialization
data class GuiContainer(
    var width: Int = 0,
    var height: Int = 0,
    var background: String = "red"
) {
    fun printMe() = println(this)
}

fun main(args: Array) {
    val container = GuiContainer().apply {
        width = 10
        height = 20
        background = "blueish"
        printMe()
    }
}

  1. Use compareBy for complex comparisons
fun sort(persons: List): List =
    persons.sortedWith(compareBy(Person::name, Person::age))
  1. Use mapNotNull to combine map and filter for non-null values
fun getPersonNames(persons: List): List =
    persons.mapNotNull { it.name }
  1. Use object to apply Singleton pattern
object PersonRepository{
    fun save(p: Person){}
    //...
}

//usage
val p = Person("Paul", 40)
PersonRepository.save(p)
  1. Do not make use of !!
//Do not use !!, there's always a better solution
person!!.address!!.street!!.length
  1. Prefer read-only data structures
//Whenever possible, do not use mutable Data Structures

val mutableList: MutableList = mutableListOf(1, 2, 3)
mutableList[0] = 0

val readOnly: List = listOf(1, 2, 3)
readOnly[0] = 0 // Does not compile
  1. Use let to execute code if receiver is not null
fun letPerson(p: Person?) {
    p?.let {
        println("Person is not null")
    }
}

Resources

Language References:
Official Reference Documentation: https://kotlinlang.org/docs/reference/
GitHub repository: https://github.com/JetBrains/kotlin
Collection of Tools and Frameworks: https://kotlin.link
Operators and Keywords Overview: https://kotlinlang.org/docs/reference/keyword-reference.html

Community:
Slack: https://kotlinlang.slack.com
Twitter: https://twitter.com/kotlin
Newsletter: http://kotlinweekly.net
Discussion: https://discuss.kotlinlang.org

Blogs:
JetBrains: https://blog.jetbrains.com/kotlin/
Simon Wirtz: https://kotlinexpertise.com

Misc:
Kotlin in Action Book: Kotlin in Action
Books: https://kotlinlang.org/docs/books.html
Online IDE: https://try.kotlinlang.org

Please follow and like this Blog 🙂

Simon is a software engineer based in Germany with 7 years of experience writing code for the JVM and also with JavaScript. He’s very passionate about learning new things as often as possible and a self-appointed Kotlin enthusiast.

Kotlin Coroutines Guide – Concurrent Programming in Kotlin

Kotlin Coroutines Guide – Concurrent Programming in Kotlin

Introduction and Motivation

In this article, you will learn about Kotlin Coroutines: What they are, what they look like, and how they work. The demonstrated code examples were tested 1.2.70 and kotlinx.coroutines 0.30.1.
Kotlin coroutines are one of the “bigger features” as indicated by the following quote, taken from JetBrains’ blog:

We all know that blocking is bad under a high load, that polling is a no-go, and the world is becoming more and more push-based and asynchronous. Many languages (starting with C# in 2012) support asynchronous programming through dedicated language constructs such as async/await keywords. In Kotlin, we generalized this concept so that libraries can define their versions of such constructs, and async is not a keyword, but merely a function.
This design allows the integration of different asynchronous APIs: futures/promises, callback-passing, etc. It is also general enough to express lazy generators (yield) and cover some other use cases.

The Kotlin team introduced coroutines to provide simple means for concurrent programming. Probably the vast majority of us already worked with some thread-based concurrency tool, e.g., Java’s concurrency API. I have worked with concurrent Java code quite a lot and mostly agree on the API’s maturity.

Java Concurrency vs. Kotlin Coroutines

If you still catch yourself struggling with threading and concurrency in Java, I can recommend the book Java Concurrency in Practice to you.

Although Java’s concurrency tooling is well-engineered, it’s often difficult to utilize and fairly tedious to use. Another problem is that Java doesn’t directly encourage non-blocking programming. You often find yourself starting threads without having in mind that they’re costly and introduce blocking computations quickly (due to locks, sleeps, waits, etc.). Applying non-blocking patterns alternatively is really hard and error-prone.

Kotlin Coroutines, on the other hand, are intended to be a lot easier and look like sequential code by hiding most of the complicated stuff from the developers. They provide a way to run asynchronous code without having to block threads, which offers new possibilities for applications. Instead of blocking threads, computations are being suspended.
Many sources describe coroutines as “light-weight threads”; they are not a thread as we know them from, e.g., Java though. Compared to threads, coroutines are mostly very cheap in their creation, and the overhead that naturally comes with threads isn’t around. One reason is that they’re not directly mapped to native threads. As you will see, coroutines are executed in thread pools that are mainly managed by the library.
Another critical difference is “limitation”: Threads are very limited because they rely on available native threads, coroutines on the other side are almost free, and thousands can be started at once (although this depends on what they compute).

Concurrent Programming Style

Different types of asynchronous/concurrent programming styles exist in various languages, for instance:
* Callback-based (JavaScript)
* Future/Promise-based (Java, JavaScript)
* Async/Await-based (C#) and more

All these concepts can be implemented with coroutines since Kotlin doesn’t dictate any of these directly.
As one additional benefit, as opposed to, for instance, callback-based programming, coroutines promote a sequential kind of asynchronous programming: Although your coroutines may execute multiple parallel computations, your code can still look sequential, just as we like it.

The Concept of Kotlin Coroutines

The term and concept “Coroutine” is anything but new. According to the Wikipedia article, it was created in 1958 already. Many modern programming languages provide native support: C#, Go, Python, Ruby, etc. The implementation of coroutines, also in Kotlin, is often based on so-called “Continuations”, which are “an abstract representation of the control state of a computer program”. We’ll learn a bit more about this in a later chapter of this article.

Getting Started with Coroutines

To set up a project with Kotlin coroutines, please use this step by step reference or simply check out my examples repository on GitHub and use it as a template.

Kotlin Coroutines Ingredients

As already hinted, the Kotlin coroutine library provides an understandable high-level API that lets us start quickly. One new modifier we need to learn is suspend, which is used to mark a method as “suspending”.
We’ll have a look at some easy examples using APIs from kotlinx.coroutines in the next section. But first, let’s learn what a suspending function is.

Suspending Functions

Coroutines rely on the suspend keyword, which is a modifier used to mark functions as “suspending”, i.e., that calls to such functions may suspend at any point. We can only call these functions from coroutines or other suspending functions.

suspend fun myMethod(p: String): Boolean {
    //...
}

As we can see in the example above, suspending functions look like a regular function with an additional modifier added to it. Keep in mind that invoking such a function from a normal function will lead to compilation errors.

We can think of a coroutine as a sequence of calls to regular as well as suspending functions. This sequence optionally provides a result at the end of its execution.

Hands-On

Let’s finally see some concrete coroutines in action. In a first example, the basics will be shown:

fun main(args: Array<String>) = runBlocking { //(1)
    val job = GlobalScope.launch { //(2)
        val result = suspendingFunction() //(3)
        print("$result")
    }
    print("The result: ")
    job.join() //(4)
}
// prints "The result: 5"

In this example, you can see two new functions, (1) runBlocking and (2) launch, both of which are examples of coroutine builders. We can utilize various builders, and they all start a coroutine with different purposes: launch (fire and forget, can also be canceled), async (returns promise), runBlocking (blocks thread) and more. We can start coroutines in different scopes. In this example, the GlobalScope is used to spawn a launch coroutine that is as a result of this limited to the application lifecycle itself. This approach is fine for most examples we will see in this article, but it will most probably not be sufficient for your real-life applications. Following the concept of “structured concurrency”, we need to confine coroutines to different scopes to make them maintainable and manageable. Read about the concept of CoroutineScope here.

Let’s observe what this code does: The inner coroutine started by (2) launch does the actual work: we call a (3) suspending function and then the coroutine prints its result. The main thread, after starting the coroutine, prints a String before the coroutine finishes.
Coroutines started by launch return a Job immediately, which we can use to cancel the computation or await its completion with (4) join() as we see here. Since calling join() may suspend, we need to wrap this call into another coroutine, which is why we use runBlocking as a wrapper. This concrete coroutine builder (1)is designed to bridge regular blocking code to suspending functions, and we can use it in main functions and tests” (Quoted API). If we removed the joining of the job, the program would stop before the coroutine can print the result.

It’s possible to spawn launch in the scope of the outer runBlocking coroutine directly. To do so, we change GlobalScope.launch to just launch. As a result, we can now also remove the explicit join since runBlocking won’t complete before all of its child coroutines finish. This example again is a demonstration of structured concurrency, a principle we want to observe in more detail next.

Structured Concurrency

As mentioned in the previous section, we can structure our coroutines in a way that they are more manageable by creating a certain hierarchy between them. Imagine you work with a user interface which, for any reason, we need to terminate at a certain point due to some event. If we started coroutines which handle certain tasks in that UI, these also should be terminated when the main task stops. With coroutines, it’s vital to keep in mind that each coroutine can run in a different scope. We often want to group multiple coroutines by a shared scope so that they can, for instance, be canceled altogether easily. Let’s re-use the basic coroutine composition we saw in the first code snippet above but now with launch running in the scope of runBlocking and slightly different tasks:

fun main(args: Array<String>) {
    runBlocking {
        launch {
            delay(500)
            println("Hello from launch")
        }
        println("Hello from runBlocking after launch")
    }
    println("finished runBlocking")
}

This code prints the following output:

Hello from runBlocking after launch
Hello from launch
finished runBlocking

This output tells us that runBlocking does not complete before its child coroutine started by launch finishes its work. Further, we can use this structure to easily delegate the cancellation on a certain coroutine down to its child coroutines:


fun main(args: Array<String>) { runBlocking { val outerLaunch = launch { launch { while (true) { delay(300) println("Hello from first inner launch") } } launch { while (true) { delay(300) println("Hello from second inner launch") } } } println("Hello from runBlocking after outer launch") delay(800) outerLaunch.cancel() } println("finished runBlocking") }

This code prints something like this:

Hello from runBlocking after outer launch
Hello from first inner launch
Hello from second inner launch
Hello from first inner launch
Hello from second inner launch
finished runBlocking

In this example, we can see a launch that creates an outer coroutine that then again launches two inner coroutines, all in the same scope. We cancel the outer coroutine which then delegates its cancelation to the inner coroutines, and nothing keeps running afterward. This approach also handles errors correctly since an exception happening in an arbitrary child coroutine will make all coroutines in its scope stop.

Custom Scope

Last but not least, we want to go a step further and create our very own CoroutineScope. In the last examples, we simply used the scope given by runBlocking, which we only did for convenience. In real-life applications, it’s necessary to create custom scopes to manage one’s coroutines effectively. The API comes with a simple builder for this: coroutineScope. It’s documentation states:

Creates new [CoroutineScope] and calls the specified suspend block with this scope. The provided scope inherits its [coroutineContext][CoroutineScope.coroutineContext] from the outer scope, but overrides context’s [Job]. This function is designed for a parallel decomposition of work. When any child coroutine in this scope fails, this scope fails, and all the rest of the children are canceled (for a different behavior see [supervisorScope]).

fun main(args: Array<String>) = runBlocking {
    coroutineScope {
        val outerLaunch = launch {
            launch {
                while (true) {
                    delay(300)
                    println("Hello from first inner launch")
                }
            }
            launch {
                while (true) {
                    delay(300)
                    println("Hello from second inner launch")
                }
            }
        }

        println("Hello from runBlocking after outer launch")
        delay(800)
        outerLaunch.cancel()
    }
    println("finished coroutineScope")
}

The code looks pretty similar to what we saw earlier, but now we run our coroutines in a custom scope. For further reference, please read this post on structured concurrency with coroutines.

Going deeper

A more vivid example is the following: Imagine, you have to send an email from your application. Requesting the recipient address and rendering the message body are two costly tasks, which are independent of each other though. Being smart and using Kotlin, you want to make use of coroutines, performing both tasks in parallel.
This is shown here:

suspend fun sendEmail(r: String, msg: String): Boolean { //(6)
    delay(2000)
    println("Sent '$msg' to $r")
    return true
}

suspend fun getReceiverAddressFromDatabase(): String { //(4)
    delay(1000)
    return "coroutine@kotlin.org"
}

suspend fun sendEmailSuspending(): Boolean {
    val msg = GlobalScope.async { //(3)
        delay(500)
        "The message content"
    }
    val recipient = GlobalScope.async { 
        getReceiverAddressFromDatabase() //(5)
    } 
    println("Waiting for email data")
    val sendStatus = GlobalScope.async {
        sendEmail(recipient.await(), msg.await()) //(7)
    }
    return sendStatus.await() //(8)
}

fun main(args: Array<String>) = runBlocking { //(1)
    val job = GlobalScope.launch {
        sendEmailSuspending() //(2)
        println("Email sent successfully.")
    }
    job.join() //(9)
    println("Finished")
}

First, like already seen in the previous example, we use a (1) launch builder inside a runBlocking builder so that we can (9) wait for the coroutine’s completion. This structure isn’t new, and neither is (2) calling a suspending function (sendEmailSuspending).
This method uses an (3) inner coroutine for getting the message content and (4) another suspend method getReceiverAddressFromDatabase for getting the address. We execute both tasks in a separate coroutine built with (5) async. Note, that the calls to delay represent a non-blocking, coroutine-suspending, alternative to Thread.sleep, which we use for mocking expensive computations here.

The async Coroutine Builder

The async builder is simple and easy in its conception. As we know from many other languages, it returns a promise, which is of type Deferred in Kotlin. By the way, promise, future, deferred or delay are often used interchangeably for describing the same concept: The async method promises to compute a value which we can wait for or request at any time.

We can observe the “waiting” on Kotlin’s Deferred object in (7) where the suspending function (6) is called with the results of both prior computations. The method await() is called on instances of Deferred which suspends until the results become available. The call to sendEmail is also part of an async builder. Finally, we await its completion in (8) before returning its result.

Shared Mutable State

It’s possible that you already had concerns about synchronization between coroutines while reading the article as I didn’t mention anything about it yet. I, at least, had this concern because coroutines can work on shared state concurrently. It’s quite evident that being aware of this is just as important as we know it from other languages like Java. We can make use of acquainted strategies like thread-safe data structures, confining execution to a single thread or using locks.
Besides the common patterns, Kotlin coroutines encourage the concept of “share by communication” (see QA).

Concretely, an “actor” can be used to represent a state that we safely share between coroutines. Coroutines can use actors to send and receive messages through them. Let’s see how this works:

Actors

sealed class CounterMsg {
    object IncCounter : CounterMsg() // one-way message to increment counter
    class GetCounter(val response: SendChannel<Int>) : CounterMsg() // a request with channel for reply.
}

fun counterActor() = GlobalScope.actor<CounterMsg> { //(1)
    var counter = 0 //(9) </b>actor state, not shared
    for (msg in channel) { // handle incoming messages
        when (msg) {
            is CounterMsg.IncCounter -> counter++ //(4)
            is CounterMsg.GetCounter -> msg.response.send(counter) //(3)
        }
    }
}

suspend fun getCurrentCount(counter: SendChannel<CounterMsg>): Int { //(8)
    val response = Channel<Int>() //(2)
    counter.send(CounterMsg.GetCounter(response))
    val receive = response.receive()
    println("Counter = $receive")
    return receive
}

fun main(args: Array<String>) = runBlocking<Unit> {
    val counter = counterActor()

    GlobalScope.launch { //(5)
            while(getCurrentCount(counter) < 100){
                delay(100)
                println("sending IncCounter message")
                counter.send(CounterMsg.IncCounter) //(7)
            }
        }

    GlobalScope.launch { //(6)
        while ( getCurrentCount(counter) < 100) {
            delay(200)
        }
    }.join()
    counter.close() // shutdown the actor
}

This example shows the usage of an (1) Actor, which is a coroutine itself working on any context. The actor is holding the (9) relevant state of this sample application, which is the mutable counter variable. Another important feature we haven’t considered so far is a (2) Channel.

Channels

Channels provide a way to transfer a stream of values, similar to what we know as BlockingQueue (enables producer-consumer pattern) in Java but without any blocking methods. Instead, send and receive are suspending functions used for providing and consuming objects from the channel, implemented with a FIFO strategy.

An actor is by default connected to such channels, which other coroutines (7) can use to communicate with other coroutines. In the example, the actor iterates over the stream of messages from its channel (for works with suspending calls) handling them according to their type: (4) IncCounter messages make the actor change its state by incrementing the counter while (3) GetCounter makes the actor return its counter state by sending an independent message to the GetCounter‘s SendChannel.
The first coroutine (5) in main launches a task that sends (7) IncCounter messages to the actor as long as the counter is less than 100. The second (6) one waits until the counter reaches 100. Both coroutines make use of the suspending function (8) getCurrentCounter, which sends a GetCounter message to the actor and suspends by waiting for receive to return.

As we can see, the entire mutable state is confined to the specific actor coroutine, which solves the problem of shared mutable state and follows the principle of share by communication.

More Features and Examples

You can find more examples and great documentation in these documents.

How it works – Implementation of Kotlin Coroutines

Coroutines do not rely on features of the operating system or the JVM. Instead, the compiler transforms coroutines and suspend functions and produces a state machine which is capable of handling suspensions in general and passing around suspending coroutines keeping their state. The concept of Continuations enables this feature. Continuations are being added to every suspending function as an additional parameter by the compiler. This technique is called “Continuation-passing style”.

Let’s see how the following function looks like after adding a continuation to it:

suspend fun sampleSuspendFun(x: Int): Int {
    delay(2000)
    return x * x
}

The compiler modifies this function to something like this:

public static final Object sampleSuspendFun(int x, @NotNull Continuation var1)

It adds another parameter, the Continuation, to it. Now, if we call this function from a coroutine, the compiler will pass the code that occurs after the sampleSuspendFun function call as a continuation. After the sampleSuspendFun completes its work, it will trigger the continuation. That’s just what we know from a callback-based programming model already but hidden by the compiler. To be honest, this is just a simplified explanation. You can learn more about the details here.

QA with Roman Elizarov (JetBrains)

I had the chance to formulate a few questions to Roman Elizarov who works for JetBrains and who’s highly responsible for Kotlin coroutines. Read what he said:

Q: When am I supposed to use coroutines and are there any use cases that still require explicit threading?

A: Rule of thumb by Roman:
Coroutines are for asynchronous tasks that wait for something most of the time. Threads are for CPU-intensive tasks.

Q: The phrase “light-weight thread” sounds kind of inappropriate to me as it obscures the fact that coroutines rely on threads and that the library executed them in a pool of threads.* I’d prefer something more simple, such as a “task” that’s being executed, stopped, etc. Why did you decide to describe them like threads anyway?

A: Roman answered, that the phrase “light-weight threads” is rather superficial, and that “coroutines are in many ways like threads from user’s standpoint.”

Q: If coroutines are similar to threads, there must be the necessity of synchronizing shared state between different coroutines, right? *

A: Roman told me, that we can still use known patterns of synchronization, but it is highly recommended to not have any mutable shared state at all when we use coroutines. Instead, coroutines encourage the “share by communication” style.

Conclusion

As opposed to Java, Kotlin encourages an entirely different style of concurrent programming, which is non-blocking and naturally doesn’t make us start vast amounts of native threads.
Writing concurrent Java code often implies starting too many threads or forgetting about proper thread pool management. This carelessness though introduces a huge overhead that results in slowed down execution. Coroutines, as an alternative, are said to be “light-weight threads”, which describes the fact that they’re not mapped to native threads and therefore don’t drag along all the risks and problems we usually have to deal with (deadlocks, starvation, e.g.). As we’ve seen, with coroutines, we normally don’t have to worry about blocking threads. Moreover, synchronization is more straightforward and ideally not even necessary as long as we pursue the “share by communication” principle.

Coroutines also enable us to work with several different kinds of concurrent programming. Many are already available, and it’s possible to add others.
Java developers, in particular, will most likely favor the async/await style which looks similar to what they already know from working with futures. It’s not just a comparable replacement but a significant improvement to what we know already.
Concurrent Java code comes with a lot of checked exceptions, defensive locking strategies and general boilerplate code. All of this can be improved by coroutines, which allow concurrent code to look sequential, be manageable and easily readable.

Perspective

Coroutines will finally be made generally available with Kotlin 1.3. The Kotlin team will remove the “experimental” nature of it, and coroutines will remain in a stable state.

Please don’t hesitate to get in touch, feedback’s always appreciated 🙂 Also if you like, have a look at my Twitter and follow if you’re interested in more Kotlin stuff 🙂 Thanks a lot. If you want to read more about Kotlin’s beautiful features I highly recommend the book Kotlin in Action and my other articles to you.

Simon

Please follow and like this Blog 🙂

Simon is a software engineer based in Germany with 7 years of experience writing code for the JVM and also with JavaScript. He’s very passionate about learning new things as often as possible and a self-appointed Kotlin enthusiast.