Search code examples
kotlintypescastingfold

Does the Kotlin Fold Function require type casting or specifying lambda type?


I am looking at the documentation for the Kotlin fold function and am having a bit of difficulty understanding what is going on. The example they provide is as follows:

val fruits = listOf("apple", "apricot", "banana", "blueberry", "cherry", "coconut")

// collect only even length Strings
val evenFruits = fruits.groupingBy { it.first() }
    .fold(listOf<String>()) { acc, e -> if (e.length % 2 == 0) acc + e else acc }

println(evenFruits) // {a=[], b=[banana], c=[cherry]}

They say there should only be a single "operation function" as an argument.

.fold(listOf<String>()) { acc, e -> if (e.length % 2 == 0) acc + e else acc }

However, in addition to the lambda, they also have the (listOf<String>()) part. While the lack of parentheses around arguments on some function calls confuses me sometimes, I imagine this can't possibly be a function call all on its own. Does the Kotlin fold Function require typecasting or specifying lambda type? If I get rid of that code snippet it breaks. I was pretty sure that the only way to specify a type was anonymous functions with a return type and not lambdas so I'm really not too sure what is going on here. I am new to Kotlin so any explanations as to what this syntax means and how the fold function works would be appreciated.

Here is the link to the documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/fold.html


Solution

  • In the linked documentation you can see there are 2 arguments:

    inline fun <T, R> Iterable<T>.fold(
        initial: R,
        operation: (acc: R, T) -> R
    ): R
    

    By the trailing lambda rule, the call is another way to write

    .fold(listOf<String>(), { acc, e -> if (e.length % 2 == 0) acc + e else acc })
    

    So initial is listOf<String>() and operation is { acc, e -> if (e.length % 2 == 0) acc + e else acc }. The reason String needs to be specified in listOf<String>() is that it helps the compiler figure out that R is List<String> and then it knows the types of both arguments in { acc, e -> ... }.

    If I get rid of that code snippet it breaks.

    If you mean just removing (listOf<String>()) then you are left with one argument, and fold requires two.

    Does the Kotlin fold Function require typecasting or specifying lambda type?

    Well, there is no typecasting or specifying lambda type in the example, so it doesn't.