jayunit100
jayunit100

Reputation: 17648

Why is this class not found?

In a scala program I've created a case to match a user, following some snippets from http://danielwestheide.com/blog/2012/11/21/the-neophytes-guide-to-scala-part-1-extractors.html

In particular, I have declared a class extending another class, and then I've attempted to case match against that class.

user match {
  case FreeUser(name) => "Hello " + name;
  case PremiumUser(name) => "hello " + name;
}

These operations both fail: it seems as though the case clause doesn't see the class definitions for the FreeUser and PremiumUser classes, which are immediately above it.

class FreeUser(val name: String) extends User{
  def unapply(user: FreeUser):Option[String] = Some(user.name);
}

//takes the object as input, returns the parameter used to construct it.
class PremiumUser(val name: String) extends User {
  def unapply(user: PremiumUser):Option[String]= Some(user.name);
}
val name = "ASDF"
val user: User = new PremiumUser("jay");
user match {
  /** This statement fails to comiple : not found, value FreeUser. **/
  case FreeUser(name) => "Hello " + name;
  case PremiumUser(name) => "hello " + name;
}

For the full class, you can reference this gist. https://gist.github.com/anonymous/e96107f91ef0262f3268

My question is, thus, simply how to reference an inner class in a case clause in Scala.

Upvotes: 1

Views: 400

Answers (2)

dursun
dursun

Reputation: 1846

both freeUser and the PreimumUser classes should be case classes as follows;

/**
 * Why does FreeUser fail to compile?
 */
object Sytax {

  object Thrice {
       def apply(x : Int) : Int = x *3
       def unapply(z : Int) : Option[Int] = if (z%3==0) Some(z/3) else None
  }

  val x = Thrice(3);

  trait User {
    def name:String;
  }

  case class FreeUser(val name: String) extends User{
    def unapply(user: FreeUser):Option[String] = Some(user.name);
  }

  //takes the object as input, returns the parameter used to construct it.
  case class PremiumUser(val name: String) extends User {
    def unapply(user: PremiumUser):Option[String]= Some(user.name);
  }
  val name = "ASDF"
  val user: User = new PremiumUser("jay");
  user match {
    case FreeUser(name) => "Hello " + name;
    case PremiumUser(name) => "hello " + name;
  }
}

Upvotes: 4

Ende Neu
Ende Neu

Reputation: 15783

The unapply method must be defined in the companion object:

object FreeUser {
  def unapply(user: FreeUser):Option[String] = Some(user.name);
}

object PremiumUser {
  def unapply(user: PremiumUser):Option[String]= Some(user.name);
}

I can't find at the moment something official about why you can't have unapply in classes, I think it's because matching on classes implicitly calls SomeObject.unapply and to do so it can't be a class (you'll have to do new SomeClass.unapply, with a singleton is much better).

Upvotes: 2

Related Questions