Mixing type parameters and abstract types in scala

风格不统一 提交于 2019-12-03 06:27:56

Compiling this with -explaintypes yields:

<console>:11: error: illegal inheritance;
 self-type GraphKind.this.G does not conform to Collection[T]'s selftype Collection[T]
         abstract class Graph[T] extends Collection[T]{
                                         ^
    GraphKind.this.G <: Collection[T]?
      Iterable[T] <: Iterable[T]?
        T <: T?
          T <: Nothing?
            <notype> <: Nothing?
            false
            Any <: Nothing?
              <notype> <: Nothing?
              false
            false
          false
          Any <: T?
            Any <: Nothing?
              <notype> <: Nothing?
              false
            false
          false
        false
      false
      GraphKind.this.Graph[T] <: Iterable[T]?
        Iterable[T] <: Iterable[T]?
          T <: T?
            T <: Nothing?
              <notype> <: Nothing?
              false
              Any <: Nothing?
                <notype> <: Nothing?
                false
              false
            false
            Any <: T?
              Any <: Nothing?
                <notype> <: Nothing?
                false
              false
            false
          false
        false
      false
    false

Now, I was about to write I don't understand how T <: T can be false -- it is almost like T was defined twice, which, of course, is the whole problem. Here:

abstract class GraphKind[T] { 

  type V <: Vertex[T] 
  type G <: Graph[T] 

  def newGraph(): G 

  abstract class Graph[T] extends Collection[T]{ 

Ok, class GraphKind is parameterized with T and type G must be a Graph[T]. Now, class Graph is also parameterized, and its parameter is also called T. To prevent confusing, let's rewrite it:

  abstract class Graph[T2] extends Collection[T2]{
    self: G =>
    def vertices(): List[V]
    def add(t: T2): Unit
    def size(): Int
    def elements(): Iterator[T2]
  }

Note that this is EXACTLY EQUAL to what you wrote. I'm just using a different name for the type parameter, so that it doesn't get confused with the T that is parameterizing GraphKind.

So, here is the logic:

G <: Graph[T]
Graph[T2] <: Collection[T2]
Graph[T2] <: G  // self type

which implies that

Graph[T2] <: Graph[T]

And, because Graph extends Collection:

Collection[T2] <: Collection[T]

But there is no guarantee that this is true. I do not understand why the problem does not show up when the inheritance is not present. Fix:

abstract class GraphKind[T] {

  type V <: Vertex
  type G <: Graph

  def newGraph(): G

  abstract class Graph extends Collection[T]{
    self: G =>
    def vertices(): List[V]
    def add(t: T): Unit
    def size(): Int
    def elements(): Iterator[T]
  }

  trait Vertex {
    self: V =>
      def graph(): G
      def value(): T
  }

}

class SimpleGraphKind[T] extends GraphKind[T] {

  type G = GraphImpl
  type V = VertexImpl

  def newGraph() = new GraphImpl

  class GraphImpl extends Graph {
    private var vertices_ = List[V]()
    def vertices = vertices_
    def add( t: T ) {  vertices_ ::= new VertexImpl(t,this) }
    override def size() = vertices_.size
    override def elements() = vertices.map( _.value ).elements
  }

  class VertexImpl(val value: T, val graph: GraphImpl) extends Vertex {
    override lazy val toString = "Vertex(" + value.toString + ")"
  }
}

Since Vertex and Graph will be tied to one instance of GraphKind, then T will be fixed to whatever it was defined for that instance. For example:

scala> new SimpleGraphKind[Int]
res0: SimpleGraphKind[Int] = SimpleGraphKind@1dd0fe7

scala> new res0.GraphImpl
res1: res0.GraphImpl = line10()

scala> res1.add(10)

scala> res1.add("abc")
<console>:9: error: type mismatch;
 found   : java.lang.String("abc")
 required: Int
       res1.add("abc")
                ^

It seems that Vertex's belonging to a particular graph and only that graph can be represented best in the type system with a nested Vertex trait in the Graph. Is what you are trying to achieve met with the following structure?

abstract class Graph[T] extends Collection[T] {
  thisGraph: Graph[T] =>

  def newGraph: Graph[T] 
  def vertices: List[Vertex[T]]
  def add(t: T): Unit
  def size: Int
  def elements: Iterator[T]

  trait Vertex[T] {
      def graph = thisGraph
      def value: T
  }
}

class SimpleGraph[T] extends Graph[T] {
  private[this] var verts = List[Vertex[T]]()

  def newGraph = new SimpleGraph[T]
  def vertices = verts
  def add(t: T) { verts ::= SimpleVertex(t) }
  override def size = verts.size
  override def elements = verts.map(_.value).elements
  def iterator = elements // the "new" elements in 2.8

  case class SimpleVertex[T](value: T) extends Vertex[T]
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!