Scala Generic inference

Viewed 83

I desire to have automatic type inference on a class with a sequence s of objects which are descendant of A, knowing that A takes generic parameters.

class A[F](val field1: F)

class G[F, Aa <: A[F], S <: Seq[Aa]](val s: S) {
  // what i have to do
}

// Evrything is ok
val gWith = new G[Int, A[Int], List[A[Int]]](List(new A(5)))

// Compilator failed: inferred type arguments [Nothing,Nothing,List[A[Int]]]
val gWithout = new G(List(new A(5)))

I will add that i explicitly need to know Aa and S types to reuse them later.

Is there any solution to dispense user to put these generic types. If not i will be happy to know why.

2 Answers

You can simplify the type parameters for your G class:

class A[F](val field1: F)

class B[F](override val field1: F) extends A[F](field1)

// Make A covariant
class G[F, S[+A] <: Seq[A]](val s: S[A[F]]) { }

// Everything is ok
val gWith = new G[Int, List](List(new A(5)))

// Also ok
val gWithout = new G(List(new A(5)))

// Ok too
val gBWithout = new G(List(new B(5)))

Working scastie: https://scastie.scala-lang.org/fmOLxCiKRBKIDFSj7stZNQ

You can achieve what you want with a type constraints

class A[F](val field1: F)

class G[F, Aa, S](val s: S)(implicit ev2: S <:< Seq[Aa], ev1: Aa <:< A[F]) {}

val gWithout = new G(List(new A(5))) // gWithout: G[Int,A[Int],List[A[Int]]] = G@79d7035

I can't really explain why it doesn't work before and why it works now, but I can tell you it is related to type inference, I have been playing in the RELP with your snippet for a while (using the '-explaintypes' flag) and I always found some strange errors like:

Nothing <: List[A[Int]]?

true

Nothing <: Any?

true

Nothing <: A[Nothing]?

true

List[A[Int]] <: Seq[Nothing]?

false

error: inferred type arguments [Nothing,Nothing,List[A[Int]]] do not conform to class G's type parameter bounds [F,Aa <: A[F],S <: Seq[Aa]]

val gWithout = new G(List(new A(5)))

List[A[Int]] <: S? false

I found this post, I haven't read it completely yet, but it seems there is a better explanation of why this now works.

Related