IntelliJ Support
Hi! I just discovered the library and I think it's very promising. I've been using Reader/Writer/State effects for a while (currently with ZPure) and have my own benchmarks (https://github.com/ghostdogpr/mtl-benchmarks) where I added Turbolift. ZPure seems a bit faster but results are ahead of all other alternatives.
One thing that would be great would be better IntelliJ support around handleWith.
For some reason it seems to struggle with overloads and can't infer the return type when calling handleWith.
Not sure if something can be done in the library to avoid that or if it has to be reported to Jetbrains.
Hello and welcome!
I just checked out your benchmark project and have a suggestion. Instead of using loops.map(...).traverseVoid, I recommend loops.foreachEff(...). It produces the same result but avoids creating an intermediate collection. It's also equivalent to traverse_ or foreachDiscard in other effect systems.
One thing that would be great would be better IntelliJ support around
handleWith.
Thanks for the heads-up! I’m not currently using IntelliJ, so I wasn’t aware of this issue.
For some reason it seems to struggle with overloads and can't infer the return type when calling
handleWith.
Since you mentioned overloading, that gives me an idea. Let's first diagnose the issue by bypassing the overloading. Here’s the affected definition. I assume you're familiar with the class FooPartiallyApplied pattern used in ZIO or Cats?
Rather than calling the overloaded apply, let's try calling id directly. It’s ugly and not meant as the final solution, but it might help us determine whether overloading is the root cause:
testTurboLift
.handleWith.id(MyReader.handler(Environment("config")))
.handleWith.id(MyState.handler(State(2)))
.handleWith.id(MyWriter.handler)
.handleWith.id(MyError.handler)
.run
Please let me know if this makes the error go away!
My bet is on the above, but here are other alternatives to explore:
- Compose all handlers into one:
testTurboLift.handleWith(
MyReader.handler(Environment("config")) &&&!
MyState.handler(State(2)) &&&!
MyWriter.handler &&&!
MyError.handler
)
.run
- Avoid
handleWithaltogether.
c.handleWith(h) is equivalent to h.handle(c). Initially, it was an exact alias, but I had to introduce overloading when enhancing the Handler type.
MyError.handler.handle(
MyWriter.handler.handle(
MyState.handler(State(2)).handle(
MyReader.handler(Environment("config")).handle(
testTurboLift
)
)
)
)
.run
- Use the Scala 2 approach.
Compute type-level set differences manually instead of relying on type inference. Since you're familiar with ZIO, you may notice similarities with provideSomeEnvironment & provideSomeLayer.
testTurboLift
.handleWith[MyError & MyWriter & MyState](MyReader.handler(Environment("config")))
.handleWith[MyError & MyWriter](MyState.handler(State(2)))
.handleWith[MyError](MyWriter.handler)
.handleWith[Any](MyError.handler)
.run
I just checked out your benchmark project and have a suggestion. Instead of using
loops.map(...).traverseVoid, I recommendloops.foreachEff(...). It produces the same result but avoids creating an intermediate collection. It's also equivalent totraverse_orforeachDiscardin other effect systems.
Thanks! I didn't manage to find it the first time. Updated the benchmark.
Rather than calling the overloaded
apply, let's try callingiddirectly. It’s ugly and not meant as the final solution, but it might help us determine whether overloading is the root cause:testTurboLift .handleWith.id(MyReader.handler(Environment("config"))) .handleWith.id(MyState.handler(State(2))) .handleWith.id(MyWriter.handler) .handleWith.id(MyError.handler) .run Please let me know if this makes the error go away!
So, it does indeed solve the issue of handleWith being not found:
However you can see run is still not recognized. That's because IntelliJ also struggle to infer the result of handleWith:
The two issues might be related, maybe it fails to find the overload because of inference, I'm not sure.
Here's a try with using nested handleWith:
There is some improvement in v110. I removed the overloading. Types inferred by IntelliJ are now less wacky (Either[Nothing] is wild), but still inaccurate. I ran out of ideas and published what I got.
What possibilities are we left with?
- A macro: just like
bindlessperforms manual type inference (union of types),handleWithcould perform set-difference. - Like you said, perhaps it's time to take it to Jetbrains. However, ZIO has been around for years, and IntelliJ shows similar inaccuracies when using
provideSomeLayer.
I gave it a try and it's quite better than before without the overloading at least.
Maybe it's not that critical since the issue is only on handleWith which should not be the main part of the code. In comparison, kyo is incorrectly inferred even when you use combinators in for comprehensions.
I opened https://youtrack.jetbrains.com/issue/SCL-23717/Wrong-types-shown-when-using-Kyo for Kyo, maybe you could do the same with Turbolift? I could do it but if you have any hints, it might help them figuring it out.