Path-dependent typing by coincidence / case

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)
    }
  }
}

Failed 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 make this work in some way:

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]
}
+4
source share
2 answers

This is not a real solution, but you can replace the internal type attribute, with the 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 work with type-dependent types, I'm interested.

0
source

Problem analysis

The error is formulated in a more interesting way if you write sampleConstas follows:

object Main {
  val sampleConst = new JobConstruction {
    override def apply(desc: Desc): Job[desc.T] = {
      val result = desc match {
        case desc2: SampleDFDesc => SampleDFJob(desc2)
        case desc2: SampleDSDesc => SampleDSJob(desc2)
      }
      result
    }
}

The error message becomes:

type mismatch;
found   : Product with Serializable with main.Job[_ >: main.Dummy with Int]{def description: Product with Serializable with main.Desc{type T >: main.Dummy with Int}}
required: main.Job[desc.T]
Note: Any >: desc.T (and Product with Serializable with main.Job[_ >: main.Dummy with Int]{def description: Product with Serializable with main.Desc{type T >: main.Dummy with Int}} <: main.Job[_ >: main.Dummy with Int]), but trait Job is invariant in type DescType. You may wish to define DescType as -DescType instead. (SLS 4.5)

This post is hard to read. The reason, apparently, is the problem of contravariance, as indicated in the fourth line, but try to make this error message first.

, , , Scala , . () , .

SampleDFJob, SampleDSJob, SampleDFDesc SampleDSDesc :

sealed trait Desc {
  type T
}

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 }
}

class DSJob[V] extends Job[V]

class DFJob extends Job[Dummy]

trait Dummy {}

object Main {
  val sampleConst = new JobConstruction {
    override def apply(desc: Desc): Job[desc.T] = {
      val result = desc match {
        case desc2: DFDesc => new DFJob
        case desc2: DSDesc[Int] => new DSJob[Int]
      }
      result
    }
  }
}

:

type mismatch;
found   : main.Job[_1] where type _1 >: main.Dummy with Int
required: main.Job[desc.T]

, Scala main.Job[_ >: main.Dummy with Int] desc.T.

: ? , result ( a Dummy, Int). Scala ( , ), , " " (, , ) . , , _ >: main.Dummy with Int, " , , " (main.Dummy Int).


, , desc.T, , Scala , ( DescType ) Job[desc.T]. , desc.T SampleDFDesc.T SampleDSDesc.T, DescType, , ( SampleDSJob extended DSJob[String] ?)


, , , ... :

, , desc.T, asInstanceOf, :

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)
    }).asInstanceOf[Job[desc.T]]
  }
}

, .


, Job, DescType (-DescType), Job.apply, :

def apply(desc: Desc): Job[_ <: desc.T]
+2

Source: https://habr.com/ru/post/1625184/


All Articles