0

I'm having some trouble implementing an immutable BST in Scala. The problem seems to be that by some reason although I've defined K to be as Ordered[K] (2nd line), it actually is being considered by the Scala compiler to be an Any. Why?

abstract class BST
sealed case class Node[K <: Ordered[K], V](key : K, value : V, left : BST, right : BST) extends BST
sealed case class Empty() extends BST

object BST {
  def empty = Empty()

  def add[K <: Ordered[K], V](key : K, value : V, tree : BST) : BST = tree match {
    case Empty() => new Node(key, value, Empty(), Empty())
    case Node(nodeKey, nodeValue, left, right) =>
      if (key < nodeKey) new Node(nodeKey, nodeValue, add(key, value, left), right)
      else if (key > nodeKey) new Node(nodeKey, nodeValue, left, add(key, value, right))
      else new Node(key, value, left, right)
  }
devoured elysium
  • 101,373
  • 131
  • 340
  • 557

4 Answers4

1

Ok guys, thanks for the help. But I think you all just got things way too complicated. The only problem seemed to be that BST had to also be BST[K, V]:

abstract class BST[K <: Ordered[K], V]
sealed case class Node[K <: Ordered[K], V](key : K, value : V, left : BST[K, V], right : BST[K, V]) extends BST[K, V]
sealed case class Empty[K <: Ordered[K], V]() extends BST[K, V]

object BST {
  def empty = Empty()

  def add[K <: Ordered[K], V](key : K, value : V, tree : BST[K, V]) : BST[K, V] = tree match {
    case Empty() => new Node(key, value, Empty(), Empty())
    case Node(nodeKey, nodeValue, left, right) =>
      if (key < nodeKey) new Node(nodeKey, nodeValue, add(key, value, left), right)
      else if (key > nodeKey) new Node(nodeKey, nodeValue, left, add(key, value, right))
      else new Node(key, value, left, right)
  }
}

This compiles and works as expected.

devoured elysium
  • 101,373
  • 131
  • 340
  • 557
0

The compiler seems to be confused by you telling it that the generic type K is a subtype of Ordered[K]. I'm a bit confused by that as well. That's like saying that A is a subtype of List[A], and I can't wrap my head around that either. How can a type be a subtype of a list of that type? Recursively defining types may work in some cases, but I don't believe this is one of them.

From the context, I feel like the actual syntax you want is [K: Ordered]. This tells the compiler to expect a generic type K for which there is an implicit Ordered[K] in scope. It is syntactic sugar that changes your Node class to look like this:

sealed case class Node[K, V](key : K, value : V, left : BST, right : BST)(implicit evidence: Ordered[K]) extends BST
Zeimyth
  • 1,389
  • 12
  • 19
0

This is because of the type erasure on the JVM - erased to Any in Scala. See this answer for example on how to work around this problem: How to pattern match on generic type in Scala?. Alternatively consider passing an implicit Ordering like this:

sealed case class Node[K, V](key : K, value : V, left : BST, right : BST,
  implicit cmp: Ordering[K]) extends BST
Community
  • 1
  • 1
yǝsʞǝla
  • 16,272
  • 2
  • 44
  • 65
0

I've gotten this down to a compiling version, it's probably not minimal though and some explicit annotations can probably be removed. If you need more explanation, please leave a comment.

abstract class BST[K : Ordering, V]
sealed case class Node[K : Ordering, V](key : K, value : V, left : BST[K, V], right : BST[K,V]) extends BST[K, V]
sealed case class Empty[K : Ordering, V]() extends BST[K, V]

object BST {
  def empty[K : Ordering, V] = Empty[K,V]()

  def add[K : Ordering, V](key : K, value : V, tree : BST[K,V]) : BST[K,V] = tree match {
    case Empty() => new Node(key, value, Empty(), Empty())
    case Node(nodeKey, nodeValue, left, right) =>
      if (implicitly[Ordering[K]].lt(key,  nodeKey)) new Node(nodeKey, nodeValue, add(key, value, left), right)
      else if (implicitly[Ordering[K]].gt(key,nodeKey)) new Node(nodeKey, nodeValue, left, add(key, value, right))
      else new Node(key, value, left, right)
  }
}
tryx
  • 975
  • 7
  • 17