Open kailuowang opened 7 years ago
FWIW, this works:
object Foo {
type MyNothing >: Nothing <: Nothing
}
case class Const[A, B >: Foo.MyNothing](a: A)
object Test {
def trav[F[_], A, B](f: A => F[B]): F[B] = ???
val c: Const[Int, Int] = trav(Const(_:Int)) //compiles
val a: Int = trav(Const(_:Int)).a //compiles too!
}
(The original example also compiles with dotty which does not suffer from nilophobia)
To me, this is not such a big deal. There are many areas where scala's type inference is not great. In such cases, you sometimes have to use type parameters (or in case matching, even introduce methods for the sole purpose of naming all the type parameters on the matched class, especially in cases with variance).
This seems to me like a case of "don't do that". Certainly making Const covariant seems like the cure being worse than the disease.
@johnynek covariant is indeed a bit risky, but what about the technique above by @smarter , that seems harmless?
Const
's phantom type can cause some type inference difficulty in scalac. Here is a minimized example:Making the phantom type covariant will helped the type inference but it's not a very obviously sound solution. See the discussion here by @ceedubs , here by @djspiewak and here by @johnynek.
Shall we live with the type inference inconvenience (not encountered very often though) or the possible ramifications of unnecessarily making the phantom type covariant?
It seems to me that neither incurs significant cost to pay but the former solution is easier to understand.