Erik Dreyer
09/27/2022, 2:29 PMEffectScope
by migrating some existing code. I’m having a bit of trouble getting something to work. See the screenshot below.
I think I have an instance of Result<E>
, and the compiler agrees, but at runtime, I’m seeing some odd and conflicting information. It seems in reality, I have a Result<Result<E>>
I’ve tried to figure out how we ended up with nested Result
, but haven’t been able to see where this is happening.Wilerson Oliveira
09/27/2022, 2:31 PMval bar = it.invoke(command) as E
I would guess this casting is the culprit. Wouldn’t val bar = it.invoke(command).bind()
work?simon.vergauwen
09/27/2022, 2:32 PMas E
passes through the Success(E)
because the Success
case is completely inlined.
Can you debug what it.invoke(command)
returns?Erik Dreyer
09/27/2022, 2:32 PMErik Dreyer
09/27/2022, 2:33 PMinvoke
method:
context(ResultEffectScope)
suspend fun invoke(request: R): E
simon.vergauwen
09/27/2022, 2:36 PMinline
code.
result {
val foo = ensureNotNull(commandHandlers[command::class]) { IllegalStateException("...") }
foo.invoke(command)
}
simon.vergauwen
09/27/2022, 2:36 PMErik Dreyer
09/27/2022, 2:36 PMErik Dreyer
09/27/2022, 2:37 PMsimon.vergauwen
09/27/2022, 2:59 PMErik Dreyer
10/01/2022, 10:58 PMfoo
of type Result<UserRegisteredEvent>
The debugger shows me the variable is this same type.
But foo.toString()
shows: Result<Result<UserRegisteredEvent>>
ok, so what does foo.getOrNull()
give me?
java.lang.ClassCastException : kotlin.Result cannot be cast to io.liquidsoftware.base.user.application.port.in.UserRegisteredEvent
Which would indicate it is indeed a double-nested Result
BUT, and here’s the kicker.
If I force cast it to the type I think it should be, it works
(foo as Result<UserRegisteredEvent>).getOrNull()
works like I expect it to?
So my question is, WTF is going on here?
Please check out this screenshotErik Dreyer
10/01/2022, 10:59 PMErik Dreyer
10/01/2022, 11:00 PMErik Dreyer
10/01/2022, 11:00 PMsimon.vergauwen
10/03/2022, 7:20 AMtoString
and the debugger (toString
) are showing two completely different things 🤯
I am making the assumption here that IDEA also uses toString
in the debugger,simon.vergauwen
10/03/2022, 7:23 AM@JvmInline
and value
class in the past year, and in some production projects we switched to using data class
rather than value class
due to this reason. To avoid the value class you could perhaps try using Either.catch
instead of runCatching
and see if Either
doesn't have this issue.
It's hard to say much beyond that without actually being able to look around in all the code to see what's going on. I've also had a bunch of issues with inline fun
and value class
, so you might also want to get rid of that in some places surrounding this code.Erik Dreyer
10/03/2022, 1:27 PM@JvmInline
or value classes. I may switch to Either just to see if I get different behavior.
I’m close to stumped. I’ll keep poking at it to see if I can figure out where the root cause issimon.vergauwen
10/03/2022, 1:29 PMResult
is value + @JvmInline
and I've seen this fail as well in combination with suspend
and inline fun
.
There are a couple edge-cases, and not sure if all of them are fixed yet.simon.vergauwen
10/03/2022, 1:30 PMinterface
+ suspend
+ inline fun
+ Result / value + @JvmInline
can cause some issues through inlining and dynamic dispatching etc, but I don't know all the compiler/low-level details. I've only got some experience debugging, and spotting problematic code 😅Erik Dreyer
10/03/2022, 1:32 PMEither
Erik Dreyer
10/03/2022, 1:33 PMsimon.vergauwen
10/03/2022, 1:34 PMErik Dreyer
10/03/2022, 3:20 PMeither
, I did the following.
1. replaced a result { … }
block with either { … }
2. added an Either.toResult()
extension method, so I didn’t have to change the return type of the method. (does one already exist in the library? I didn’t see it)
This fixed the issue I was seeing, which probably verifies @simon.vergauwen’s suspicions abovesimon.vergauwen
10/03/2022, 3:51 PMEither<Throwable, A>
-> Result<A>
conversion method, nor the other way around 🤔 That would be a welcoming addition.