I Love Kotlin

7-12-2024

kotlin-logo

Overview

I really do love Kotlin. Here are some snippets of neat things I've enjoyed doing in the language. My thinking is to update this blog post with snippets as I use them.

Mutable Property Reference

7-12-2024

For my Starfield Mod Manager I have a config command that, among other things, allows the users to toggle various boolean variables to true or false. When I parse the command, if the first arg is one of the boolean settings, I check the next arg to see if I should update the boolean to true or false. I had the following code repeated a number of times, where each block was checking the flag, updating the setting, printing the result, and saving.

when {

    //...

    args.first() == "verbose" -> {

        val verbose = args.getOrNull(1) == "true"

        toolConfig.verbose = verbose

        println("Updated verbose to ${toolConfig.verbose}")

        save()

    }



    args.first() == "autodeploy" -> {

        val autoDeploy = args.getOrNull(1) == "true"

        toolConfig.autoDeploy = autoDeploy

        println("Updated autodeploy to ${toolConfig.autoDeploy}")

        save()

    }

}

I'm a fan of not implementing DRY (Don't Repeat Yourself) "prematurely", as I've found anticipating DRY can add to a lot of unnecessary abstraction. But when I wanted to make the true/false parsing more sophisticated, I decided it was time to factor out a method that would work for each setting. I started with a more sophisticated flag parser using a when statement:

private fun getNewValue(args: List<String>, current: Boolean) {

    val flag = when (args.getOrNull(1)) {

        "true" -> true

        "false" -> false

        else -> !current

    }

}

I love the conciseness of the when statement, especially when checking equality. This gave me a way to quickly set the flag to the user passed arg, or just toggle the existing value.

Because Kotlin lets me pass a reference to a mutable var, I can pass reference to the var itself to the function, and both get and set that var, which means I can update the function to look like this:

private fun updateFlag(args: List<String>, flag: KMutableProperty0<Boolean>) {

    val newValue = when (args.getOrNull(1)) {

        "true" -> true

        "false" -> false

        else -> !flag.get()

    }

    flag.set(newValue)

    println("Updated ${flag.name} to ${flag.get()}")

    save()

}

I pass in the var (KMutableProperty0<Boolean>) as a parameter named flag. Then I can get the current value by calling flag.get() and later set the property by calling flag.set(newValue). I can even use the built-in Kotlin reflection to print out a message with the actual name of the passed in var by using flag.name.

This allows me to vastly simplify my calling code to call this function and pass in the args and the reference to the proper boolean setting:

args.first() == "verbose" -> updateFlag(args, toolConfig::verbose)

args.first() == "autodeploy" -> updateFlag(args, toolConfig::autoDeploy)

args.first() == "use-my-docs" -> updateFlag(args, toolConfig::useMyDocs)

args.first() == "version" -> viewAppVersion()