I'm writing a trait to describe node-like objects in a Hierarchical structure (like a graph). My working code is below:
trait Hierarchical[T <: Hierarchical[_]] {
// The parents will be a list of some arbitrary Hierarchical
val parents: List[Hierarchical[_]] = Nil
var children: List[Hierarchical[T]] = List()
def addChild(child: Hierarchical[T]): Unit = {
children ++= List(child)
}
}
abstract class NonRootNode(override val parents: List[Hierarchical[_]])
extends Hierarchical[NonRootNode] {
}
abstract class RootNode extends Hierarchical[NonRootNode] {
final override val parents = Nil
}
I have some tests which reflect this behavior:
import org.scalatest.FlatSpec
class DummyRoot extends RootNode
class DummyNonRoot(override val parents: List[DummyRoot])
extends NonRootNode(parents)
class TestUtil extends FlatSpec {
"A RootNode" should "not have parents" in {
val dummyRoot = new DummyRoot
assert(dummyRoot.parents.isEmpty)
}
"A NonRootNode" should "have parents when constructed with them" in {
val dummyRoot = new DummyRoot
assert(dummyRoot.parents.isEmpty)
val dummyNonRoot = new DummyNonRoot(List(dummyRoot))
dummyRoot.addChild(dummyNonRoot)
assert(dummyNonRoot.parents.contains(dummyRoot))
assert(dummyRoot.children.contains(dummyNonRoot))
}
}
However, I find the API to be a bit unwieldy in the second test. I shouldn't need to add a child to the root node explicitly since I've already specified the child's parents. I'd like to remove this from the public API, so my thought is to modify NonRootNode
's constructor behavior to call this for each of the parents. Specifically, I want to write:
abstract class NonRootNode(override val parents: List[Hierarchical[_]])
extends Hierarchical[NonRootNode] {
//for each parent, add `this` to its children
parents.map{p=>p.addChild(this)}
}
However, when I add this line, I get the following error:
Error:(19, 29) type mismatch;
found : NonRootNode
required: Hierarchical[_$3]
parents.map{p=>p.addChild(this)}
I'm not entirely sure why I'm getting this compiler error. My understanding of Hierarchical[_]
is any Hierarchical
, but I could be mistaken. In any case, I think I'm close to my desired behavior. What am I doing wrong?