Is there a doc, guide or article on how to manage ...
# arrow
e
Is there a doc, guide or article on how to manage stacktrace while working with https://arrow-kt.io/learn/typed-errors/ ?
e.g. having such code
Copy code
Command.EVALUATE -> {
  val expr = parseTokens(tokens, errors)
  val either = either { interpreter.evaluate(expr) }
  when (either) {
    is Either.Left -> {
      System.err.println(either.value.message)
      System.err.println("[line ${either.value.lineNumber}]")
      exitProcess(70)
    }
    is Either.Right -> either.value.toLoxString().let { println(it) }
  }
}
need to get stacktrace in
Either.Left
branch
y
try using the
traced
Raise
builder
👍 1
e
Like this
Copy code
Command.EVALUATE - > {
  val expr = parseTokens(tokens, errors)
  val either =
  either {
    traced(
      block = {
        interpreter.evaluate(expr)
      },
      trace = { trace, error - >
        println("Trace: $trace")
      },
    )
  }
  when(either) {
    is Either.Left - > {
      System.err.println(either.value.message)
      System.err.println("[line ${either.value.lineNumber}]")
      exitProcess(70)
    }
    is Either.Right - > either.value.toLoxString().let {
      println(it)
    }
  }
}
? Strange it gives
Copy code
Trace: Trace(exception=arrow.core.raise.Traced: kotlin.coroutines.cancellation.CancellationException should never get swallowed. Always re-throw it if captured.This swallows the exception of Arrow's Raise, and leads to unexpected behavior.When working with Arrow prefer Either.catch or arrow.core.raise.catch to automatically rethrow CancellationException.)
y
Yeah Trace does have that because that's the exception it refers to. However, you can still access
printStackTrace
and other similar methods to get the stack trace you want
gratitude thank you 1
e
Yes, thank you, this
Copy code
println("Trace: ${trace.stackTraceToString()}")
gives me stacktrace
y
One tiny issue I have with
traced
is that it doesn't have an obvious way to combine the error with the stack trace and have that be raised instead. I'm pretty sure, though, that you can just do:
Copy code
public inline fun <Error, OtherError, A> Raise<Error>.withErrorTraced(
  transform: (Trace, OtherError) -> Error,
  block: Raise<OtherError>.() -> A
): A {
  contract {
    callsInPlace(block, EXACTLY_ONCE)
  }
  withError({ _: OtherError -> error("should never be called") }) {
    traced({ return block(this) }) { trace, error -> raise(transform(trace, error)) }
  }
}
s
@Youssef Shoaib [MOD] since Trace is experimental (🧌) we can change
Trace
to be a
data class
and include the
Error
.. That is a source compatible change, but a binary breaking one. In this case I think it's okay as long as it's across a minor version
y
Hmmmm, good idea, but wouldn't we thus also need to add a type parameter, which would make it not source-compatible? I also wrote up this PR to make
withErrorTraced
the primitive and
traced
an instance of it
kodee loving 1
s
Ah, good point it might indeed not be source compatible indeed. A second operator is certainly warranted. Thanks for the PR I'll look at it asap 👍
e
This
withErrorTraced
is to be able to handle both error and Trace in
Either.Left
branch?
Copy code
val expr = parseTokens(tokens, errors)
val either: Either < InterpreterErrorWithTrace, Any ? > =
  either {
    withErrorTraced(
      transform = { trace, interpreterError - >
        InterpreterErrorWithTrace(
          interpreterError = interpreterError,
          trace = trace
        )
      }
    ) {
      interpreter.evaluate(expr)
    }
  }

when(either) {
  is Either.Left - > {
    System.err.println(either.value.interpreterError.message)
    System.err.println("[line ${either.value.interpreterError.lineNumber}]")
    System.err.println("Trace: ${either.value.trace.stackTraceToString()}")
    exitProcess(70)
  }
  is Either.Right - > {
    println(either.value.toLoxString())
  }
}
seems like this works for me