Reputation: 1132
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
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
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