How (not) to debug inline functions


#1

I think that inline functions are a very useful addition to Kotlin. I’m wondering though, what the golden path for debugging with inline function should be.

Example:

val l = listOf(1, 2, 3, 4)
val res = l.foldRightIndexed(0) { index, elem, akk ->
    if (index % 2 == 0) {  // just some code. Really could be anything useful. Breakpoint here and step through code
        akk + index * 3
    } else {
        akk + index - 4
    }
}

println(res)

Stepping through that code also steps into kotlin.collections.foldRightIndexed which I don’t want to happen. I suppose that there are some inline functions you’d like to step into and others you just never would like to see (e.g. forEach).

Before filing an issue for this, I’d be happy to hear how others are dealing with this and if there’s anything that can be done from IDEAs side to improve the debugging experience (due to the inlined nature of those functions).


#2

Hi! For me it seems the piece of general problem with debugging any code written too tightly, you know, the same as debugging the chain of “myList.map(someLambda).groupBy(otherLambda)” etc.

In your particular example I usually set a breakpoint (or execute “run to…”) on the line with “if (index…” - e.g. I often prefer to set several breakpoints in a snippet of code instead of setting one and then using “step over / step into”.

Other than that I can step into foldRightIndexed and then execute “step out”… probably (?)

I understand that is not the most convenient way. However I’m not sure it is worth of filing an issue unless one could tell exactly what behavior is preferred. Anyway the same problem exists in any of similar languages and I’ve never seen it well-solved…

So what could be proposed at all? An option to restrict stepping into library function? Or “step into” variant which only works with functions defined in the same file? This is a not an easy question… :frowning:


#3

This is exactly, why I am asking what other think how this should behave. Right now, I find the debugging experience very unpleasant with a lot of distracting jumps to random places.

I think that filtering even is a better example because the behavior that I mean is more pronounced. I think that IDEA should not step into the surrounding code of the inline function (unless forced with a force step into). For example, forEach() is similar to the language construct for and it should behave in the same way in the debugger.

Is this even technically possible to implement? Does the debugger know which code was generated by an inline function and which wasn’t?


#4

Debugger is already improved in stepping through inline functions. The default behavior is ‘not to step into lambda argument during step over’, but maybe this should be improved for some inline functions like forEach, synchronized and similar (KT-4841).

The stepping in your example with foldRightIndexed is a bug (you can follow KT-12016).

So if you find some behavior unpleasant - please, report an issue with full description in your tracker.

Also you can skip all functions from Kotlin Standard library during debug: just add a filter kotlin.* into Settings -> Build… -> Debugger -> Stepping -> Do not skip into classes.


#5

This is quite annoying when the function is rather large and the scaffolding in between its “location” and use is large (step into will not do the right thing either). The solution is probably to have a third “step file” option that steps to the next line in the file, either inside the closure, or whatever comes after it if the closure is never invoked.