4

How can I design a method which returns a path dependent type? In the following example, I deliberately want Vertex to be path dependent on Tree such that it is forbidden to mix vertices across trees (and this is just an example):

trait Tree {
  trait Vertex
  def root: Vertex
  def addChild(parent: Vertex): Vertex
}

trait TreeFactory { def make: Tree }

Now the following cannot be constructed:

def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = {
  val t  = f.make
  var sq = IndexedSeq(t.root)
  var m  = Map.empty[t.Vertex, t.Vertex]
  for( i <- 1 to 100) {
    val p = sq(util.Random.nextInt(sq.size))
    val c = t.addChild(p)
    m    += c -> p
    sq  :+= c
  }
  (t, m)
}

Because obviously the map I return should not have keys and values of type Tree#Vertex but of the path dependent vertex...

error: type mismatch;
 found   : scala.collection.immutable.Map[t.Vertex,t.Vertex]
 required: Map[Tree#Vertex,Tree#Vertex]
Note: t.Vertex <: Tree#Vertex, but trait Map is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Tree#Vertex`. (SLS 3.2.10)
           (t, m)
               ^

If I try to decouple tree creation and parent-child map build-up:

def test(t: Tree): Map[t.Vertex, t.Vertex] = {
  var sq = IndexedSeq(t.root)
  var m  = Map.empty[t.Vertex, t.Vertex]
  for (i <- 1 to 100) {
    val p = sq(util.Random.nextInt(sq.size))
    val c = t.addChild(p)
    m    += c -> p
    sq  :+= c
  }
  m
}

This fails for another reason: "error: illegal dependent method type"

0__
  • 64,257
  • 16
  • 158
  • 253

3 Answers3

3

My twisted mind came up with this one. I hope there is a more elegant solution:

trait Gagaism {
  val tree: Tree
  val map: Map[tree.Vertex, tree.Vertex]
}

def test(f: TreeFactory) = new Gagaism {
  val tree = f.make
  val map = {
    var sq = IndexedSeq(tree.root)
    var m = Map.empty[tree.Vertex, tree.Vertex]
    for (i <- 1 to 100) {
      val p = sq(util.Random.nextInt(sq.size))
      val c = tree.addChild(p)
      m    += c -> p
      sq  :+= c
    }
    m
  }
}
0__
  • 64,257
  • 16
  • 158
  • 253
  • 1
    If you're not happy using -Ydependent-method-types then this (packaging up the depended-on value with the dependent type(s)) is what I would recommend. – Miles Sabin Jul 23 '11 at 12:06
  • Thank you miles, that works. Since, as I figured, you don't need `-Xexperimental`, I wonder why this must be explicitly enabled? – 0__ Jul 26 '11 at 19:47
1

You can enable experimental support for dependent method types with -Xexperimental -Ydependent-method-types, I think.

0__
  • 64,257
  • 16
  • 158
  • 253
Jean-Philippe Pellet
  • 56,205
  • 18
  • 161
  • 223
0

I don't understand the type system well enough to explain why your first attempt doesn't work, but this is the pattern I usually follow (with bounded abstract type members), which does compile. It'd be nice to see implementations of Tree and TreeFactory to be more confident though.

package trees

trait Tree {
  trait Vertex

  type V <: Vertex
  def root: V
  def addChild(parent: V): V
}

trait TreeFactory { def make : Tree }

object Test {
  def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = {
    val t = f.make
    var sq = IndexedSeq(t.root)
    var m = Map.empty[t.Vertex, t.Vertex]
    for (i <- 1 to 100) {
      val p = sq(util.Random.nextInt(sq.size))
      val c = t.addChild(p)
      m += c -> p
      sq :+= c
    }
    (t, m)
  }
}
Alex Cruise
  • 7,667
  • 1
  • 24
  • 36
  • 1
    In my concrete case, vertices are associated with orderings, and I want to confine each ordering to be comparable with elements retrieved from the same ordering. The orderings maintain an `Int` tag, so technically there is nothing wrong with mixing the orderings; the path dependent types provide a nice way to prevent this from happening, as comparing across orderings (or trees here) is almost certainly a bug. In fact, after I got my code working (the gagaism way), the compiler indeed found at least one spot where I committed that exact mistake. Was kind of a nice confirmation of this approach – 0__ Jul 21 '11 at 07:24