2

I have three F-Bound types A, B & C, where B is parametrized by A, and C is parametrized by B (and hence also by A). I can instantiate A and B, but when I try to instantiate C, the compiler is unable to infer the types. If I give it the types explicitly, everything works - but it seems rather silly that these types are lost (is this due to type erasure?).

sealed trait A[AA <: A[AA]] {
  self =>
  val data: String
}

case class AInst(data: String) extends A[AInst]

sealed trait B[BB <: B[BB, AA], AA <: A[AA]] {
  self: BB =>
  val content: AA
}

case class BInst[AA <: A[AA]](content: AA) extends B[BInst[AA], AA]

sealed trait C[CC <: C[CC, BB, AA], BB <: B[BB, AA], AA <: A[AA]] {
  self: CC =>
  val content: BB
}

case class CInst[BB <: B[BB, AA], AA <: A[AA]](content: BB) 
     extends C[CInst[BB, AA], BB, AA]

val a1 = new AInst("A1")
val b1 = BInst(a1)
val c1 = CInst[BInst[AInst],AInst](b1)

Is there a work around, where I do not have to specify the types for CInst specifically?

I am currently using type parametrization to implement the F-Bounds, but would switching to abstract type members solve this problem? How would the class look like then?

Karalga
  • 495
  • 4
  • 11
  • I had example here: https://stackoverflow.com/questions/1154571/scala-abstract-types-vs-generics/10891994#10891994 – ayvango Aug 20 '17 at 14:11

1 Answers1

1

How about that:

... //A,AInst,B,BInst without changes

sealed trait C[CC <: C[CC, BB, AA], BB <: B[BB, AA], AA <: A[AA]] {
  self: CC =>
  val content: B[BB, AA] //`B[BB, AA]` instead of `BB`
}

case class CInst[BB <: B[BB, AA], AA <: A[AA]](content: B[BB,AA]) extends C[CInst[BB, AA], BB, AA]

Usage:

scala> val a1 = new AInst("A1")
a1: AInst = AInst(A1)

scala> val b1 = BInst(a1)
b1: BInst[AInst] = BInst(AInst(A1))

scala> val c1 = CInst(b1)
c1: CInst[BInst[AInst],AInst] = CInst(BInst(AInst(A1)))

It didn't work before as compiler seen BB as BInst[AA <: A[AA]], so my B[BB,AA] just lifted BB into B[BInst[AInst], AInst].

P.S. With type members you still pushed to pass the types to your case classes somehow, so no big difference.

dk14
  • 22,206
  • 4
  • 51
  • 88
  • Great, thanks! I was so close... The type definitions are becoming slightly unwieldy, I wonder if that is also a form of code smell. – Karalga Apr 16 '15 at 13:06
  • It depends on how you see them :) I see them as compile-time `def`s [like here](http://stackoverflow.com/a/29470018/1809978). But compile'r type inferrence might not be so clear, and actually it very depends on your domain-logic, you might really not need them – dk14 Apr 16 '15 at 13:09