Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a Promise be covariant

In Scala, a Future is defined to be covariant whereas a Promise is invariant. It is said that a Promise can almost be made contravariant (https://issues.scala-lang.org/browse/SI-7467). Why is this the case?

like image 266
Dominic N. Avatar asked Mar 13 '17 16:03

Dominic N.


2 Answers

If promise were covariant you would be able to do:

val p: Promise[Any] = Promise[String]()
p.success(1)

thereby completing a Promise[String] with an Int which would be unsafe.

like image 200
Lee Avatar answered Sep 17 '22 14:09

Lee


A Promise is a mutable API, which does not fare well with covariance. Futures don't suffer this problem because you cannot manually complete them like you do with a Promise.

Let's say we have:

class Animal
class Cat extends Animal
class Dog extends Animal

If you want Promise[A] to be covariant over A, that means we want Promise[Cat] <: Promise[Animal] and Promise[Dog] <: Promise[Animal]. Let's suppose we can do this.

Okay, so let's say we have a Promise[Cat]:

val p: Promise[Cat] = ...

By our supposition, it's also a Promise[Animal]:

val q: Promise[Animal] = p

Promise has a method called complete which accepts a Try[T], which is also covariant. This means that a Try[Dog] is also a Try[Animal]. See where this is leading?

We'd be able to call:

val value: Try[Dog] = ...

q.complete(value)

Which would be legal, because we're trying to complete a Promise[Animal] with a Try[Animal], but oops, we also just tried to complete a Promise[Cat] with a Promise[Dog].

like image 21
Michael Zajac Avatar answered Sep 20 '22 14:09

Michael Zajac