mj1261829
mj1261829

Reputation: 1319

Scala - not a case class nor does it have method .unapply

I am quite new to Scala and got a few unresolved problems with the following code:

   object exprs{
      println("Welcome to the Scala worksheet")

      def show(e: Expr): String = e match {
        case Number(x) => x.toString
        case Sum(l, r) => show(l) + " + " + show(r)
      }

      show(Sum(Number(1), Number(44)))
    }

    trait Expr {
      def isNumber: Boolean
      def isSum: Boolean
      def numValue: Int
      def leftOp: Expr
      def rightOp: Expr
      def eval: Int = this match {
        case Number(n) => n
        case Sum(e1, e2) => e1.eval + e2.eval
      }
    }

    class Number(n: Int) extends Expr {
      override def isNumber: Boolean = true

      override def isSum: Boolean = false

      override def numValue: Int = n

      override def leftOp: Expr = throw new Error("Number.leftOp")

      override def rightOp: Expr = throw new Error("Number.rightOp")
    }

    class Sum(e1: Expr, e2: Expr) extends Expr {
      override def isNumber: Boolean = false

      override def isSum: Boolean = true

      override def numValue: Int = e1.eval + e2.eval

      override def leftOp: Expr = e1

      override def rightOp: Expr = e2
    }

I get the following errors:

Error: object Number is not a case class, nor does it have an unapply/unapplySeq member

Error: not found: value Sum

How to resolve them? Thanks in advance

Upvotes: 1

Views: 3837

Answers (1)

sarveshseri
sarveshseri

Reputation: 13985

In Scala case class are like class with extra goodies + some other properties.

For a normal class,

class A(i: Int, s: String)

You can not create its instance like this,

val a = A(5, "five")   // this will not work

You will have to use new to create new instance.

val a = new A(5, "five")

Now lets say we have case class,

case class B(i: Int, s: String)

We can create a new instance of B like this,

val b = B(5, "five")

The reason this works with case class is because case class have an auto-created companion objects with them, which provides several utilities including an apply and unapply method.

So, this usage val b = B(5, "five") is actually val b = B.apply(5, "five"). And here B is not the class B but the companion object B which is actually provieds apply method.

Similarly Scala pattern matching uses the unapply (unapplySeq for SeqLike patterns) methods provided by companion object. And hence normal class instances do not work with pattern matching.

Lets say you wanted to defined a class and not a case class for some specific reason but still want to use them with pattern-matching etc, you can provide its companion object with the required methods by yourselves.

class C(val i: Int, val s: String) {
}

object C {

  def apply(i: Int, s: String) = new C(i, s)

  def unapply(c: C) = Some((c.i, c.s))

}

// now you can use any of the following to create instances,

val c1 = new C(5, "five")

val c2 = C.apply(5, "five")

val c3 = C(5, "five")

// you can also use pattern matching,

c1 match {
  case C(i, s) => println(s"C with i = $i and s = $s")
}

c2 match {
  case C(i, s) => println(s"C with i = $i and s = $s")
} 

Also, as you are new to learning Scala you should read http://danielwestheide.com/scala/neophytes.html which is probably the best resource for any Scala beginner.

Upvotes: 4

Related Questions