Search code examples
scalafor-comprehension

Why ambiguous reference error while using Left without parameters type?


I found "ambiguous reference to overloaded definition" while trying to practice scala interview question.

I was trying to find the outcome of following code block which results in compilation error :

Code :

for {
  v1 <- Left[Int,Int](1)
  v2 <- Right(2)
  v3 <- Right(3)
  v4 <- Left(4)
} yield v1 + v2 + v3 + v4

Error :

<pastie>:17: error: ambiguous reference to overloaded definition,
both method + in class Int of type (x: Char)Int
and  method + in class Int of type (x: Byte)Int
match argument types (Nothing)
} yield v1 + v2 + v3 + v4
                     ^

Why Scala compiler gives ambiguous reference error when we specified type only on v1 field but not on v4 ?

I also tried following version with different parameter type in v1 and v4 and it worked !

for {
  v1 <- Left[String,Int]("1")
  v2 <- Right(2)
  v3 <- Right(3)
  v4 <- Left[Int, Int](4)
} yield v1 + v2 + v3 + v4

And the output is :

res20: scala.util.Either[Any,Int] = Left(1)

I tried with one more version which also resulted into error :

for {
  v1 <- Left(1)
  v2 <- Right(2)
  v3 <- Right(3)
  v4 <- Left(4)
} yield v1 + v2 + v3 + v4

output :

<console>:17: error: value + is not a member of Nothing
       } yield v1 + v2 + v3 + v4

How exactly the for comprehension works here with Left and Right ? Why the first and last case are not working in my example ?


Solution

  • It's because there's no common inferred types and you didn't specify the types for all the Either.

    So

    scala> for (v1 <- Right(2)) yield v1
    res13: scala.util.Either[Nothing,Int] = Right(2)
    

    Solution is to give them common types

    for {
      v1 <- Left[Int,Int](1)
      v2 <- Right[Int,Int](2)
      v3 <- Right[Int,Int](3)
      v4 <- Left[Int,Int](4)
    } yield v1 + v2 + v3 + v4
    

    Which gives Left(1). This result makes sense due to Either being right-biased and for comprehension serving as a flatMap.

    According to the documentation: "Either is right-biased, which means that Right is assumed to be the default case to operate on. If it is Left, operations like map, flatMap, ... return the Left value unchanged"
    https://www.scala-lang.org/api/2.12.0/scala/util/Either.html