I have a ADT as follows:
sealed trait Tree[A]
case object EmptyTree extends Tree[Nothing]
case class Leaf[A](value: A) extends Tree[A]
case class Node[A](op: Seq[A] => A, branches: Tree[A]*) extends Tree[A]
When i try to build a function to randomly create Trees i get a problem with the EmptyTree, the type system does not let go through
def create(acc: Tree[A], currentDepth: Int): Tree[A] = currentDepth match {
case maxDepth => Leaf(terminalSet(r.nextInt(terminalSet.length)))
case 0 => {
val op_pos = r.nextInt(fSetLength)
val branches: Seq[Tree[A]] = for (i <- 0 to r.nextInt(fSetLength)) yield create(EmptyTree, currentDepth+1)
Node(functionSet(op_pos)._1, branches:_*)
}
case _ => {
if (r.nextFloat() <= probF) {
val op_pos = r.nextInt(fSetLength)
val branches = for (i <- 0 to r.nextInt(fSetLength)) yield create(EmptyTree, currentDepth + 1)
Node(functionSet(op_pos)._1, branches:_*)
}
else
Leaf(terminalSet(r.nextInt(terminalSet.length)))
}
}
create(EmptyTree, 0)
basically in create(EmptyTree, currentDepth + 1) it complains that it is expecting a Tree[A] and is receiving a EmptyTree.type
The compiler objections are justified. The compiler expects
Tree[A]and you are passingEmptyTree, whose super type isTree[Nothing]. A priori, there's no subtyping relationship between these two types.What you want is
Treeto be covariant: ifX <: YthenTree[X] <: Tree[Y]. Then, asNothing <: Afor anyAyou getEmptyTree.type <: Tree[A]and you can always passEmptyTreewhenever you need aTree[A].The syntax for declaring the
Aparameter inTreecovariant isTree[+A]; change that and your code should compile.This is a good post on covariance and contravariance in Scala: Be friend with covariance and contravariance
UPDATE After your questioning answer I have actually looked at your constructors for
Treeand, as defined, you cannot makeTreecovariant. Sadly, the compiler won't complain (you see, it should actually complain more). YouropinNodeis contravariant onSeq[A], and thus you cannot makeNodecovariant. At this point you might be thinking:Well, through making its supertype
Treecovariant Node becomes so in practice.scalacshould actually check that all sub type constructors of a covariant one are (or could be made) covariant. Anyway, code showing this follows:UPDATE 2 Back to your original question :) I'd leave your
Treetype invariant, and have anEmptyTree[A]()case class; it is a pity that there are no parameterless value classes.