Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to debug Kotlin sequences / collections

Take the following one-liner, which can be expressed as a series of operations on a collection or a sequence:

val nums = (10 downTo 1)
        // .asSequence() if we want this to be a sequence
        .filter { it % 2 == 0 }
        .map { it * it }
        .sorted()
        // .asList() if declaring it a sequence

println(nums)   // [4, 16, 36, 64, 100]

Let's say I want to see the elements at each step, they would be (from deduction):

[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[10, 8, 6, 4, 2]
[100, 64, 36, 16, 4]
[4, 16, 36, 64, 100]

Unfortunately, there's no good way to either debug this with a debugger or log these values for later inspection. With good functional programming constructs, entire methods can be rewritten as single statements like this but there seems to be no good way to inspect intermediate states, even counts (10, 5, 5, 5 here).

What's the best way to debug these?

like image 764
Will Avatar asked Jan 15 '17 23:01

Will


3 Answers

You can log the intermediate values (lists) with

fun <T> T.log(): T { println(this); this }

//USAGE:
val nums = (10 downTo 1)
    .filter { it % 2 == 0 }.log()
    .map { it * it }.log()
    .sorted().log()

This will work as desired since in your example you work with collections, not sequences. For lazy Sequence you need:

// coming in 1.1
public fun <T> Sequence<T>.onEach(action: (T) -> Unit): Sequence<T> {
    return map {
        action(it)
        it
    }
}

fun <T> Sequence<T>.log() = onEach {print(it)}

//USAGE:
val nums = (10 downTo 1).asSequance()
    .filter { it % 2 == 0 }
    .map { it * it }.log()
    .sorted()
    .toList()
like image 138
voddan Avatar answered Oct 24 '22 21:10

voddan


In latest Intellij Idea when adding a breakpoint you have an option to set it to not inspect whole expression but only a Lambda body.

enter image description here

Then in the debug itself you can see what is happening inside of your Lambda.

enter image description here

But this is not the only way. You can also use Run to cursor (Alt + F9).

like image 35
Januson Avatar answered Oct 24 '22 19:10

Januson


I think the current correct answer is that you want the Kotlin Sequence Debugger plugin, which lets you use IntelliJ's lovely Java stream debugger with Kotlin sequences.

Note that (unless I'm doing something wrong) it doesn't appear to work with collections, so you will have to convert the collection to a sequence in order to debug it. Easy enough using Iterable.asSequence, and a small price to pay -- you can always revert that change once you are done debugging.

like image 24
Tim Keating Avatar answered Oct 24 '22 20:10

Tim Keating