Skip to content

["Request"] Improve stacktracer for Exceptions thrown from either and either.eager #2647

@danitutu

Description

@danitutu

Arrow version: 1.0.1

When an exception is thrown inside an either or either.eager.

The exception loses the information about the place it was thrown.

My guess is that it's because of kotlin inlining.

Is there any way we can keep the stacktrace containing the line numbers of the stacktrace calls?

Here's an example:

package com.x

import arrow.core.Either
import arrow.core.computations.either
import org.junit.jupiter.api.Test

class T {
    @Test
    fun myTest() {
        MyClass.aFun()
    }
}

object MyClass {
    fun aFun(): Either<String, Unit> = either.eager {
        println("c")
        bFun()
    }
    fun bFun(): Either<String, Unit> = either.eager {
        println("a")
        println("b")
        throw RuntimeException("the exception")
    }
}

The exception (look mostly at the top):

the exception
java.lang.RuntimeException: the exception
	at com.x.MyClass$bFun$$inlined$eager$1.invokeSuspend(Effect.kt:28)
	at com.x.MyClass$bFun$$inlined$eager$1.invoke(Effect.kt)
	at com.x.MyClass$bFun$$inlined$eager$1.invoke(Effect.kt)
	at arrow.continuations.generic.DelimContScope.invoke(DelimContScope.kt:91)
	at arrow.continuations.Reset.restricted(Reset.kt:37)
	at com.x.MyClass.bFun(Test.kt:28)
	at com.x.MyClass$aFun$$inlined$eager$1.invokeSuspend(Effect.kt:27)
	at com.x.MyClass$aFun$$inlined$eager$1.invoke(Effect.kt)
	at com.x.MyClass$aFun$$inlined$eager$1.invoke(Effect.kt)
	at arrow.continuations.generic.DelimContScope.invoke(DelimContScope.kt:91)
	at arrow.continuations.Reset.restricted(Reset.kt:37)
	at com.x.MyClass.aFun(Test.kt:26)
	at com.x.T.myTest(Test.kt:10)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
...

The line from the exception are either missing or are numbers that do not identify the lines that are being executed.

Without using either or either.eager:

    fun aFun(): Either<String, Unit> {
        println("c")
        return bFun()
    }
    fun bFun(): Either<String, Unit> {
        throw RuntimeException("the exception")
    }
}
the exception
java.lang.RuntimeException: the exception
	at com.x.MyClass.bFun(Test.kt:19)
	at com.x.MyClass.aFun(Test.kt:16)
	at com.x.T.myTest(Test.kt:9)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

As you can see the code clearly states the stacktrace lines.

It's easier to try in the IDE, click the class name and see where it points to.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions