0

Try to use type alias with EitherT get compilation error

type FuEiErr[T] = Future[Either[Error, T]]
type FuEiErrInt = Future[Either[Error, Int]]

case class Error(msg: String)
def fA(x:Int): FuEiErr[Int] = Future(Right(x))  // compile error
def fB(x:Int): FuEiErr[Int] = Future(Right(x))  
// def fA(x:Int): FuEiErrInt = Future(Right(x)) // ok
// def fB(x:Int): FuEiErrInt = Future(Right(x)) 

@main def TestEitherT(): Unit = 
  (for {
    a  <- EitherT(fA(7))
    b  <- EitherT(fB(42))
  } yield { (b) }).value.map {
    case Left(err)  => println(s"Error: ${err.msg}")
    case Right(res) => println(s"Result: ${res}")
  }

Got error "No given instance of type cats.Functor[F] was found for parameter F of method map in class EitherT where: F is a type variable with constraint >: [X0] =>> scala.concurrent.Future[Either[Error, X0]] scala.concurrent.Future[X0] and <: [_] =>> Any

Thanks for help!

8
  • Just for the record, EitherT is usually a bad idea and using cats with Future is a bad idea as well. Commented Jun 3, 2024 at 13:24
  • 1
    @LuisMiguelMejíaSuárez just curious, why? :) Commented Jun 3, 2024 at 17:27
  • @DmytroMitin a lot of reasons really, typed errors are IMHO a bad idea most of the time. EitherT doesn't play well with concurrency. cats makes zero guarantees about Future execution order, especially with traverse and especially when combined with EitherT. Is all just a mix for a disaster. IME is way simpler to just stick to concrete IO and use the failure channel or custom ADTs. Commented Jun 3, 2024 at 20:17
  • 1
    Well, heavily use EitherT in playframework environment (client and server side), so far no problems. Future is much easier to use than IO, don't need pure functionality, cancelability, ... Having already a bunch of libraries to manage (+ migration from Scala/Playframework 2 -> 3), don't want to pay the price for additional dependency and complexity with cats effect (or ZIO). Commented Jun 4, 2024 at 6:56
  • @RobertJo well if you want to use Future cool, do what you prefer. But don't mix it with cats, it will cause you trouble. Unless you don't care at all about the execution behaviour of your operations, at that point then don't use Future at all in any case. Commented Jun 4, 2024 at 13:03

1 Answer 1

4

Just type parameters were not inferred. Try

for {
  a <- EitherT[Future, Error, Int](fA(7))
  b <- EitherT[Future, Error, Int](fB(42))
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yeah if you check this scastie: scastie.scala-lang.org/BalmungSan/W8Ai5HhZTXGbStcXgqSlSw/18 you can see the inferred type for a is something very weird like EitherT[[X] =>> Future[Either[Error, X] | X], Error, Int] which is what then fails the summon for the Functor. - This seems to be a bug / regression in the compiler, since this works in Scala 2: scastie.scala-lang.org/BalmungSan/W8Ai5HhZTXGbStcXgqSlSw/24 my advice for @RobertoJo would be to open a ticket about it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.