shaktimaan
shaktimaan

Reputation: 12092

Scala pattern matching with Option type

I am trying to define a binary tree with the following definition:

  trait Node {
    val label: Int
  }
  case class BranchNode(override val label: Int, left: Option[Node], right: Option[Node]) extends Node
  case class LeafNode(override val label: Int) extends Node

and then define a simple printTree method using Scala's pattern matching as below:

  def printTree(aTree: Option[Node]): Unit = aTree match {
    case None => print(".")
    case Some(LeafNode(label)) => print(label)
    case Some(BranchNode(label, left, right)) => "{" + printTree(left) + label + printTree(right) + "}"
  }

The Intellij IDE warns me that the match may not be exhaustive. An Option can have None or Some as it's values. In case of Option[Node], it can either be Some(LeafNode) or Some(BranchNode). What other cases am I overlooking?

Upvotes: 2

Views: 3464

Answers (2)

prayagupadhyay
prayagupadhyay

Reputation: 31262

Definitely its a compiler warning, see below I'm breaking your code, by passing printTree(Option(IWillBreakYou(2)))

match error

      trait Node {
        val label: Int
      }
      case class BranchNode(override val label: Int, left: Option[Node], right: Option[Node]) extends Node
      case class LeafNode(override val label: Int) extends Node

      case class IWillBreakYou(override val label: Int) extends Node

      def printTree(aTree: Option[Node]): Unit = aTree match {
        case None => print(".")
        case Some(LeafNode(label)) => print(label)
        case Some(BranchNode(label, left, right)) => "{" + printTree(left) + label + printTree(right) + "}"
      }

      val leftNode = Option(LeafNode(2))
      val rightNode = Option(LeafNode(3))
      printTree(Option(BranchNode(1, leftNode, rightNode)))

      printTree(Option(IWillBreakYou(2))) //this will fail

The reason is since you are taking Option[Node] AND anybody can extend Node (within/outside of package unless protected) which you are not considering in your matches.

So, adding failsafe match case _ would fix the future error.

def printTree(aTree: Option[Node]): Unit = aTree match {
        case None => print(".")
        case Some(LeafNode(label)) => print(label)
        case Some(BranchNode(label, left, right)) => "{" + printTree(left) + label + printTree(right) + "}"
        case _ => println("do nothing")
 }

Upvotes: 3

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149636

Since your trait isn't sealed, it is open for extension in different packages. IntelliJ is warning you of the future possibility that anyone extending this trait and forgetting to implement an additional case may cause a MatchError. If you want to limit it's extension, use:

sealed trait Node

Upvotes: 6

Related Questions