Austin
Austin

Reputation: 1132

Scala: Either with parameterized function type

Should Either work with parameterized functions?

case class FunOrSeq[T1, T2](e: Either[Function1[T1, T2], Iterable[T1]])

def f: Int => Int = x => x

scala> FunOrSeq(Left(f))
<console>:11: error: type mismatch;
 found   : scala.util.Left[Int => Int,Nothing]
 required: Either[T1 => Int,Iterable[T1]]
          FunOrSeq(Left(f))

Which was surprising to me - it works with explicit types:

scala> case class FunOrSeq[T1, T2](e: Either[(Int => Int), Iterable[T1]])
defined class FunOrSeq

scala> FunOrSeq(Left(f))
res6: FunOrSeq[Nothing,Nothing] = FunOrSeq(Left(<function1>))

Upvotes: 0

Views: 1708

Answers (2)

Rex Kerr
Rex Kerr

Reputation: 167911

The problem is that because the Iterable branch also gets a T1, the Function1 branch isn't allowed to fix it as Int (it's not just Function1; having the same type parameter used for both covariant and contravariant type arguments tends to be tough on the type inference engine). You can insist that the compiler allow this by adding more type parameters and letting the Iterable be narrower than the Function1:

case class FunOrSeq[A, B, AA <: A](e: Either[A => B, Iterable[AA]])

scala> FunOrSeq(Left(f))
res0: FunOrSeq[Int,Int,Nothing] = FunOrSeq(Left(<function1>))

And if you want them to really be the same, you can add an implicit to force them to be the same:

case class FunOrSeq[A, B, AA <: A](e: Either[A => B, Iterable[AA]])(implicit ev: A =:= AA)

scala> FunOrSeq(Left(f))
res1: FunOrSeq[Int,Int,Int] = FunOrSeq(Left(<function1>))

Upvotes: 3

Falmarri
Falmarri

Reputation: 48615

I'm not sure what the reason is here behind the compiler's decisions, but the fact that you have T1 on both sides of the either is confusing the type system. If you add a parameter to make Iterable[T3] different from T1, it seems to work.

scala> case class FunOrSeq2[T1, T2, T3](e: Either[Function1[T1, T2], Iterable[T3]])
defined class FunOrSeq2

scala> FunOrSeq2(Left(f2))
res12: FunOrSeq2[Int,String,Nothing] = FunOrSeq2(Left(<function1>))

Upvotes: 1

Related Questions