typelevel / cats

Lightweight, modular, and extensible library for functional programming.
https://typelevel.org/cats/
Other
5.26k stars 1.21k forks source link

`Const` type inference glitch #1608

Open kailuowang opened 7 years ago

kailuowang commented 7 years ago

Const's phantom type can cause some type inference difficulty in scalac. Here is a minimized example:

   def trav[F[_], A, B](f: A => F[B]): F[B] = ???
    case class Const[A, B](a: A)
    val c: Const[Int, Int] = trav(Const(_:Int))   //compiles
    val a: Int  = trav(Const(_:Int)).a    //doesn’t compile

[error] found : Int => Const[Int,Nothing] [error] required: Int => Const[Int,B] [error] val a: Int = trav(Const(_:Int)).a

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.

smarter commented 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)

johnynek commented 7 years ago

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.

kailuowang commented 7 years ago

@johnynek covariant is indeed a bit risky, but what about the technique above by @smarter , that seems harmless?