I have the following code
def addKitten(kitten: Kitten): EitherT[Future, GenericError, UUID] = {
val futureOfEither = db.run { // returns a Future[Int] with the number of rows written
kittens += kitten
}.map {
case 1 => kitten.uuid.asRight
case _ => GenericError.SpecificError.asLeft
}
EitherT(futureOfEither)
}
Where SpecificError
is a subclass of GenericError
. For some reason it does not compile complaining that a SpecificError
is not a GenericError
. Is it right?
I mean, Either[A, B]
should be immutable, so why not making it covariant? Am I missing something?
The same issue for XorT
and OptionT
was raised here. The reply was:
In Scala, variance has both positives and negatives (perhaps that's how they decided on variance notation! :P). These pros/cons have been discussed numerous times in various venues, so I won't go into them now, but in my opinion at the end of the day you kind of have to settle on "to each their own".
I think this "to each their own" perspective implies that you can't force variance on a type constructor. A concrete example is
scalaz.Free
in the 7.0 series. It forces theS
type constructor to be covariant. At the time I often wanted to wrap aCoyoneda
inFree
. The most recent versions of Cats and Scalaz have theCoyoneda
essentially built into theFree
, so this particular use might not be as desired now, but the general principle applies. The problem is thatCoyoneda
is invariant, so you simply couldn't do this (without a mess of@uncheckedVariance
)! By making type constructor parameters invariant, you may end up forcing people to be more explicit about types, but I think that it beats the alternative, where you can prevent them from being able to use your type at all.