sealed trait Desc {
type T
}
trait Dataset[A] {
def toDS[A] = new Dataset[A] {}
}
trait DataFrame {}
sealed trait DFDesc extends Desc {
type T = Dummy
}
sealed trait DSDesc[A] extends Desc {
type T = A
}
trait JobConstruction {
def apply(desc: Desc): Job[desc.T]
}
sealed trait Job[DescType] {
def description: Desc { type T = DescType }
}
abstract class DSJob[V] extends Job[V] {
def result(con: JobConstruction): Dataset[V]
}
abstract class DFJob extends Job[Dummy] {
def result(con: JobConstruction): DataFrame
}
trait Dummy {}
case class SampleDFDesc() extends DFDesc
case class SampleDFJob(description: SampleDFDesc) extends DFJob {
override def result(con: JobConstruction) = new DataFrame {}
}
case class SampleDSDesc() extends DSDesc[Int]
case class SampleDSJob(description: SampleDSDesc) extends DSJob[Int] {
override def result(con: JobConstruction) = new Dataset[Int] {}
}
object Main {
val sampleConst = new JobConstruction {
override def apply(desc: Desc): Job[desc.T] = desc match {
case desc2: SampleDFDesc => SampleDFJob(desc2)
case desc2: SampleDSDesc => SampleDSJob(desc2)
}
}
}
Fails to compile with
/tmp/sample.scala:73: error: type mismatch;
found : this.SampleDFJob
required: this.Job[desc.T]
case desc2: SampleDFDesc => SampleDFJob(desc2)
^
/tmp/sample.scala:74: error: type mismatch;
found : this.SampleDSJob
required: this.Job[desc.T]
case desc2: SampleDSDesc => SampleDSJob(desc2)
EDIT:
I would like to get this to work in some kind:
case class SampleDepDesc(df: SampleDFDesc) extends DSDesc[Int]
case class SampleDepJob(description: SampleDepDesc) extends DSJob[Int] {
override def result(con: JobConstruction): Dataset[Int] = con(description.df).result(con).toDS[Int]
}
It is not a real solution, but you could replace type inside trait, with type parameter, this code compiles:
sealed trait Desc[T]
trait Dataset[A]
trait DataFrame
sealed trait DFDesc extends Desc[Dummy]
sealed trait DSDesc[A] extends Desc[A]
trait JobConstruction {
def apply[A](desc: Desc[A]): Job[A]
}
sealed trait Job[A] {
def description: Desc[A]
}
abstract class DSJob[V] extends Job[V] {
def result: Dataset[V]
}
abstract class DFJob extends Job[Dummy] {
def result: DataFrame
}
trait Dummy
case class SampleDFDesc() extends DFDesc
case class SampleDFJob(description: SampleDFDesc) extends DFJob {
def result = new DataFrame {}
}
case class SampleDSDesc() extends DSDesc[Int]
case class SampleDSJob(description: SampleDSDesc) extends DSJob[Int] {
def result = new Dataset[Int] {}
}
val sampleConst = new JobConstruction {
override def apply[A](desc: Desc[A]): Job[A] = desc match {
case desc2: SampleDFDesc => SampleDFJob(desc2)
case desc2: SampleDSDesc => SampleDSJob(desc2)
}
}
As for how to make path dependent types work, I am curious myself.