Photo by Anne Nygård on Unsplash

The history of programming languages is ripe with evolution. Existing languages constantly evolve and new languages are created to address the emerging needs. Sometimes there are radical, revolutionary breakthroughs, with a complete paradigm shift, but often there are just gradual improvements and refinements. The latter is the topic of this story. The practice of programming at any given era usually goes ahead of capabilities that programming languages provide, while programming language designers recognize it and catch up to fulfill the demand. Let us see some examples to the point.

In early languages, you had to write a lot of repetitive…


Photo by Davies Designs Studio on Unsplash

Once upon a time coroutines were introduced to Kotlin and they were lightweight. We could launch a multitude of coroutines and we needed a way to communicate between those coroutines without running into a dreaded “mutable shared state” problem.

Thus Channel was added as an inter-coroutine communication primitive. The channels are wonderful. Channels support one-to-one, one-to-many, many-to-one, and many-to-many communication between coroutines, and every value that is sent to the channel is received once.


Photo by Li Yang on Unsplash

At the dawn of software engineering computers were programmed directly in machine code, then in assembly, and only later in higher-level languages. Computers are imperative. They operate by executing instructions that mutate their state, stored in registers and memory. Naturally, the same was true about programming languages. In the old world of expensive computers with limited resources, the primary concern was an efficient translation of higher-level abstractions into low-level code.

It used to be a normal practice to write software in a way that mimics the actual computer architecture with thousands of global variables that are being mutated by various…


Photo by Ben Wicks on Unsplash

Repetitio est mater studiorum (Latin, repetition is the mother of all learning).

Repetition is great for study, but a bane of software development. Repetitive code is boring and error-prone. Let’s look at a hypothetical example inspired by imperative UI frameworks that are still being used a lot nowadays, even though their heyday is past. We might find ourselves having to write code like this:

applicationWindow.title = "Just an example"
applicationWindow.position = FramePosition.AUTO
applicationWindow.content = createContent()
applicationWindow.show()

Referencing applicationWindow object over and over again is very explicit but it is not pretty. …


Photo by John Mark Arnold on Unsplash

What are Kotlin Exceptions and how should you use them? To figure it out let’s look at their origins first. Exceptions came to Kotlin from Java. The story with exceptions in Java is complicated, though. I’ll give a brief overview.

Java has a unique concept of checked exceptions that were designed to solve the problem of verbose and error-prone error-handling (pun intended). In languages predating Java, like in venerable C, you have to write code like shown in this snippet when doing basic input/output:

file = fopen("file.txt", "r");
if (file == NULL) {
// handle error & return
}
//…


Photo by Linus Mimietz on Unsplash

Threads are heavy-weight and have substance. With threads, we can get a reference to some kind of current Thread object, examine its properties, modify its thread-local variables, and otherwise manipulate it. It is no surprise that people with the thread-programming background and education, who are coming to programming with coroutines, are looking for some kind of Coroutine object they can get hold of. However, there is none. Coroutines are phantom, ephemeral, insubstantial. There are good reasons for this state of affairs and some non-trivial consequences. Let’s dig in.

Consider the following suspending function foo that performs some work and then…


Photo by Riccardo Pelati on Unsplash

Kotlin Coroutines are typically used for asynchronous programming. However, the underlying design of coroutines and their implementation in Kotlin compiler are quite universal, solving problems beyond asynchronous programming. Let’s take a look at one such problem that can be elegantly solved with coroutines— writing deeply recursive functions.

Setup

Consider a tree data structure. For this example, let’s use this simple binary tree where each Tree node has a reference to its left and right children:

class Tree(val left: Tree?, val right: Tree?)

The depth of the tree is defined as the length of the longest path from its root to its…


DeadEnd by Austin Mulhern

Throughout most of my early professional career, I programmed in languages where you terminate or separate statements with a semicolon; it was like an ideograph distinguishing coders from laypeople. I had a motor reflex to type a semicolon (;) without having to think about it. So when I got involved in the early discussions about the new language that JetBrains was working on back in 2010, the language that would be later called Kotlin, I was not thrilled about the proposal to drop the mandatory semicolons. Who minds the semicolons I thought. I had quite a strong opinion about the…


Vernier Caliper by Michael Brace

When we work on a piece of software, being it an application or a library, we often focus on its functional requirements. They are usually quite easy to directly observe and test; functional requirements are featured in software marketing materials in the form of “feature matrix” that compares different products. Yet, many non-functional aspects of software, also known as quality attributes or qualities for short, such as reliability, efficiency, security, maintainability, usability, etc¹ can be important, too. They are not as easy to measure, though.

Consider, for a example, a task of picking a library to parse some data interchange…


Photo by Annie Spratt on Unsplash

A little over a year ago I announced big conceptual shift in the design of Kotlin Coroutines called Structured Concurrency. From that moment on, it took our team about a month to make the first stable 1.0.0 release of kotlinx.coroutines library. After a year of further work, kotlinx.coroutines had added stable support for cold flows that integrate nicely with reactive streams. The library had reached version 1.3.2 by now. It is good time to look back and see how it all worked out — what was great, what could be improved.

Structured Concurrency accomplished more than we hoped for. Originally…

Project Lead for the Kotlin Programming Language @JetBrains

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store