I Love Kotlin
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()