· 8 min read

Kotlin Koans for Perplexed Pythonistas

A Decorative Image

A lesser light asks Ummon, What are the activites of a sramana? Ummon answers, I have not the slightest idea. The dim light then says, Why haven’t you any idea? Ummon replies, I just want to keep my no-idea.

Dan Simmons, the Fall of Hyperion

Confessions of a Python Girlie

It’s time to put it out there. I am not a software developer. I can’t even confidently say I’ve ever developed actual software, as in a standalone program or app that can be installed and used outside of an IDE runtime environment. I wrote many a python script, sometimes with objects and classes and even a __main__; I wrote unit tests and testing frameworks and scripts for packaging and deployment and CI/CD; I maintained and debugged and eventually extended production code for research tooling that was written by much more experienced people than myself. I’m a bit like a second language learner: I understand a lot, enough to read and hold my own in conversations and even provide criticism (my CRs used to put fear into my coworkers!), but not enough to, say, write a poem.

All of this is to say, there are many things about programming I only know about from hearsay, from glimpsing fancy decorators in code written by my elders and other kinds of arcane lore. Kotlin is the first language I’m venturing to learn in a long while (not counting the extremely superficial acquaintance I made with JavaScript last year), and I intend to use it for Actual Software Development. I am taking it rather seriously - doing the full Android Developer bootcamp, not skipping any subjects etc. On the other hand, I can’t really ignore the fact that I’ve been writing piles of Python code over the past year. I have some assumptions, some habits and automatic approaches to tasks, and approximate understanding of core concepts that will need to be challenged.

Kotlin Koans: introduction

After completing the first section of the Kotlin bootcamp, I wanted to play around with the basics a bit more, just to make sure I really get it. Lo and behold, the “Learn more” page of the bootcamp suggested Kotlin Koans as a good hands-on tutorial. I was familiar with the concept of a koan since Mr. Nice’s foray into Clojure, and of course I wanted my own version of that juicy content.

The thing that I noticed the most when doing the koans was where exactly I got stuck - it was the smallest things. I was confused by most one-liners, while other tasks really felt like stating the obvious. I suppose it all depends on where you’re coming from, after all, the “Welcome” page of the Kotlin bootcamp did mention Java and C# as prerequisites. Let me share some of my confusion with you.

Hello World

The task at hand was very simple:

Replace TODO with a function that returns “OK”

fun start(): String = TODO()

“a function”, they said. “return”, they said. Naturally, I followed the instructions, added a scope and a return value.

A Decorative Image

Oy vey.

A Decorative Image

Let’s see what compiler has to say.

A Decorative Image

A Decorative Image

But.. but.. you said function should RETURN “OK”!

I took the Michaelangelo route and started removing everything unnecessary, ending up with the solution:

fun start(): String = "OK"

Note to self - a function that returns a string can just be a literal string.

Named Arguments

Make the function joinOptions() return the list in a JSON format (for example, [a, b, c]) by specifying only two arguments.

I know some of those words!

fun joinOptions(options: Collection<String>) =
    options.joinToString(TODO())

The gist is that the library function joinToString has named arguments for formatting options. The task specified a prefix [, a separator , and a suffix ], BUT the function also specifies default values for the arguments if no override is provided. The default value for the separator is indeed , so no need to specify that, leaving only 2 arguments, as required.

fun joinOptions(options: Collection<String>) =
    options.joinToString(prefix = "[", postfix = "]")

Default Arguments

Change the declaration of the foo function in a way that makes the code using foo compile.

A Decorative Image

The calls to foo function don’t pass some of the arguments specified in the function, so I suppose I should add some default values…?

A Decorative Image

This is ubiquitous in Python, but maybe not in other languages?

fun foo(name: String = "", number: Int = 42, toUpperCase: Boolean = false) =
        (if (toUpperCase) name.uppercase() else name) + number

fun useFoo() = listOf(
        foo("a"),
        foo("b", number = 1),
        foo("c", toUpperCase = true),
        foo(name = "d", number = 2, toUpperCase = true)
)

Triple Quoted Strings

Replace the trimIndent call with the trimMargin call taking # as the prefix value so that the resulting string doesn’t contain the prefix character.

const val question = "life, the universe, and everything"
const val answer = 42

val tripleQuotedString = """
    #question = "$question"
    #answer = $answer""".trimIndent()

fun main() {
    println(tripleQuotedString)
}

Triple-quoted strings == multiline strings. Calling trimIndent() on a string removes indentations in the multilined string. Calling trimMargin() does the same but you can also pass a parameter to specify a margin character (| by default, but could be anything). In this case, replacing the call to trimIndent() with trimMargin("#") produces the desired formatting. I found string formatting to be a very useful tool in Python, so it’s good to know Kotlin has some built-ins for that.

String Templates

Triple-quoted strings are not only useful for multiline strings but also for creating regex patterns as you don’t need to escape a backslash with a backslash. Using the month variable, rewrite the following pattern in such a way that it matches the date in the format 13 JUN 1992 (two digits, one whitespace, a month abbreviation, one whitespace, four digits).

val month = "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)"

fun getPattern(): String = TODO()

The digits and the whitespaces are straightforward - """\d{2} (TODO) \d{4}""". Next, since the month variable is already formatted as a regex for one of the month names, we can plop it as is in the middle of the string - """\d{2} $month \d{4}""".

A Decorative Image

On a more personal note, regexes were in the intersection of my Linguistics major and CompSci minor in Uni, so there’s always a warm place in my heart for them.

Nullable Types

Learn about null safety and safe calls in Kotlin and rewrite some given Java code so that it only has one if expression.

public void sendMessageToClient(
    @Nullable Client client,
    @Nullable String message,
    @NotNull Mailer mailer
) {
    if (client == null || message == null) return;

    PersonalInfo personalInfo = client.getPersonalInfo();
    if (personalInfo == null) return;

    String email = personalInfo.getEmail();
    if (email == null) return;

    mailer.sendMessage(email, message);
}

In Java, calling client.getPersonalInfo() on a null client will result in a runtime error, and so we need to ensure the variable is not null before we try to call its internal field or method. Kotlin enables us to call a variable’s field in a safe way, first checking whether the variable itself is null (and returning null if it is), and only then accessing the field itself. This saves us some lines of code, which is always a good thing!

fun sendMessageToClient(
        client: Client?, message: String?, mailer: Mailer
) {
    val email = client?.personalInfo?.email
    if (email != null && message != null) {
        mailer.sendMessage(email, message)
    }
}

Nothing Type

Specify Nothing return type for the failWithWrongAge function. Note that without the Nothing type, the checkAge function doesn’t compile because the compiler assumes the age can be null.

import java.lang.IllegalArgumentException

fun failWithWrongAge(age: Int?)    {
    throw IllegalArgumentException("Wrong age: $age")
}

fun checkAge(age: Int?) {
    if (age == null || age !in 0..150) failWithWrongAge(age)
    println("Congrats! Next year you'll be ${age + 1}.")
}

fun main() {
    checkAge(10)
}

A Decorative Image

The solution is literally spelled out in the task - just add : Nothing to the function declaration. However, I was thrown off by this way more than I should have. Most of the Python I dealt with wasn’t typed or was weakly typed, so I haven’t seen many examples where tight control over return types, especially nulls and nothings, would be significant. I’m sure it will come useful at some point in the future, in which case you can expect a throwback!

Lambdas

Pass a lambda to the any function to check if the collection contains an even number. The any function gets a predicate as an argument and returns true if at least one element satisfies the predicate.

Ah, lambdas, another warm and fuzzy memory from Semantics A (or is it a cold and prickly memory? Semantics A was a long time ago).

fun containsEven(collection: Collection<Int>): Boolean =
        collection.any {TODO}

A lambda expression is like a short-hand way to create a function. I could do a loop iterating over all members of the collection within the scope of the original containsEven function, or I could utilize collection.any but still pass it a fully-fledged function. Instead I can take just the actually functional bit of computation I need to do (e.g. modulo 2), and shove it into curly brackets, and badabing badaboom we’ve got ourselves a function!

fun containsEven(collection: Collection<Int>): Boolean =
        collection.any { x: Int -> x % 2 == 0 }

Looking at the suggested solution though, it’s even shorter than what I came up with - {it % 2 == 0}. I assume it is interpreted as whichever member the collection.any passes to the lambda. Nifty!

Onwards and Upwards

This Pythonista is a little less confused! Still, this is very much a beginner-level stage I’m at. I’m sure there will be more confusion as I venture deeper into Kotlin development, and I plan on sharing all of that confusion with y’all.

In other news, chemo is tough. I am grateful for my amazing family and my lovely friends, who’ve all banded up together to keep me well taken care of. That, and a gynormous pot of chicken soup courtesy of my mom, is what keeps me going in these rainy days. Also, respect to all bald people - how on earth do you not freeze every single moment of your life??

Peace and love.