Tips for golfing in Kotlin

22

5

Given Google's recent announcement of official Kotlin support for Android development, I thought it might be timely to poll the community for some awesome golfing tips for this relatively new JVM language.

Kotlin includes a unique combination of features among it's JVM siblings which makes it potentially attractive for golfing:

So, how do I squeeze the last few bytes out of my Kotlin program? One tip per answer, please.

Tyler MacDonell

Posted 2017-06-14T21:15:09.417

Reputation: 701

2Would there be interest in a golfing language that shortens some of Kotlin's longer names, but doesn't add a lot of extras (at least initially)? I am thinking of making common 1 letter, making string char counts shorter and adding single letter strings with only 1 quote mark? – jrtapsell – 2017-09-18T18:03:11.993

*Common functions – jrtapsell – 2017-09-18T18:15:36.400

Seems Kotlin golfing interest is not that high :( http://data.stackexchange.com/codegolf/query/793250/top-kotlin-golfers

– jrtapsell – 2018-01-28T22:58:01.730

I plan to start submitting more Kotlin solutions! I'll have to check out that project of yours as well. – Tyler MacDonell – 2018-01-30T00:48:08.993

Answers

4

Extension Functions

Extension functions can really help to reduce the names of built in methods, and chains of them, an example could be:

fun String.c() = this.split("").groupingBy{it}.eachCount()

but this only helps if:

A) The call is long enough to cancel out the definition

B) The call is repeated

Use of lambdas rather than methods

Lambdas can return without using the return keyword, saving bytes

KotlinGolfer

A project I have started here which takes pretty Kotlin code and gives posts with tests and TIO links automatically

jrtapsell

Posted 2017-06-14T21:15:09.417

Reputation: 915

4

Use + instead of toString

As one might expect, String overloads the + operator for string concatenation, like so.

print("Hel" + "lo")

However, checking the docs tells us that it accepts Any?, not just String. As stated:

Returns a string obtained by concatenating this string with the string representation of the given other object.

In other words, String + anything makes sure to call .toString() on the right hand side before concatenating. This allows us to shorten it.toString() to ""+it, a massive 8 byte savings at best and 6 bytes at worst.


Use fold instead of joinToString

Related to the above, if you're calling map and then joinToString, you can shorten that by using fold instead.

list.map{it.repeat(3)}.joinToString("")
list.fold(""){a,v->a+v.repeat(3)}

snail_

Posted 2017-06-14T21:15:09.417

Reputation: 1 982

TIL fold is a thing, nice – Quinn – 2019-05-13T18:29:07.697

3

Starting from 1.3 you can omit args in fun main() completely, thus shaving off 18 chars (that is, the length of args:Array<String>).

shabunc

Posted 2017-06-14T21:15:09.417

Reputation: 169

1

Defining Int's in params

This will likely have some pretty specific use cases where it may be worth it, but in recent question I golfed I found I could save a few bytes by defining my variable as optional parameters rather than defining them in the function.

Example from my answer to this question:

defining variable in the function:

fun String.j()={var b=count{'-'==it}/2;var a=count{'/'==it};listOf(count{'o'==it}-a,a-b,b)}

defining variables as params:

fun String.j(b:Int=count{'-'==it}/2,a:Int=count{'/'==it})=listOf(count{'o'==it}-a,a-b,b)

because var a= is the same length as a:Int= it will be the same number of bytes to define them (this is only the case for Int) however since I now only have 1 line in the function I can drop the {} and I also drop a single ; (the other is replaced with a ,)

So if there are any functions that require defining an Int, and would be a 1 liner if you didn't define the int in the function - then doing it as a parameter will save a couple bytes

Quinn

Posted 2017-06-14T21:15:09.417

Reputation: 1 153

0

The to infix function

There is a standard infix function named to that creates Pairs of two values. It's commonly used with mapOf() for defining Maps but it's can potentially be a lot shorter than the Pair() constructor.

Pair(foo,bar)   //constructor
foo to bar      //best case 
(foo)to(bar)
((foo)to(bar))  //worst case

snail_

Posted 2017-06-14T21:15:09.417

Reputation: 1 982

0

Destructuring in lambda arguments

Say you want to accept a Pair<*,*> in a lambda. Normally, handling this would be annoying. As an example, here's a lambda that takes a Pair and checks if the two values are equal:

{it.first==it.second}

This is long-winded and clumsy. Luckily, Kotlin allows you to destructure any destructable type (any type that implements componentN() methods, such as Pair, Triple etc.) as arguments to a lambda. So, we can rewrite this in the following way:

{(a,b)->a==b}

It looks similar to pattern matching a tuple in something like F#, and it is in many cases. But a wide variety of types in Kotlin support destructuring (MatchResult is a useful one.)

You can take more arguments, though. Say your lambda had to take a Pair and an additional value. You'd simply write the lambda signature like this:

(a,b),c->  // pair first
a,(b,c)->  // pair second

snail_

Posted 2017-06-14T21:15:09.417

Reputation: 1 982