Modeling with Scala case class
case-class, extractor, pattern-matching, scala
Solution
There are several reasons why case classes shouldn't be subclassed. In your case, the problem becomes that `OK` is another type than (a subtype of) `Response`, therefore the match fails (even if the arguments match, the type doesn't match).
You will want custom extractors, instead. For example:
case class Response(code: Int, body: String)
object OK {
def apply(body: String) = Response(200, body)
def unapply(m: Response): Option[String] = m match {
case Response(200, body) => Some(body)
case _ => None
}
}
def test(m: Response): String = m match {
case OK(_) => ":-)"
case _ => ":-("
}
test(Response(300, "Hallo")) // :-(
test(Response(200, "Welt")) // :-)
test(OK("Welt")) // :-)
There are few more examples of custom extractors in this thread.
Problem
I'm attempting to model responses from REST APIs as case classes which I can use pattern matching on. I thought it would be a good fit assuming inheritance, but I see that this is deprecated. I know there are already questions related to case classes and inheritance, but my question is more about how you would model the following the "right way" here without inheritance. I started with the following two case classes, which work fine: ``` case class Body(contentType: String, content: String) case class Response(statusCode: Int, body: Body) ``` i.e. a REST call would return with something like: ``` Response(200, Body("application/json", """{ "foo": "bar" }""")) ``` which I could pattern match like: ``` response match { case Response(200, Body("application/json", json)) => println(json) case Response(200, Body("text/xml", xml)) => println(xml) case Response(_,_) => println("Something unexpected") } ``` etc. which works fine. Where I ran into trouble is: I'd like helper extensions for these case classes, such as: ``` case class OK(body: Body) extends Response(200, body) case class NotFound() extends Response(404, Body("text/plain", "Not Found")) case class JSON(json: String) extends Body("application/json", json) case class XML(xml: String) extends Body("text/xml", xml) ``` so that I can do simplified pattern matches like this: ``` response match { case OK(JSON(json)) => println(json) case OK(XML(xml)) => println(xml) case NotFound() => println("Something is not there") // And still drop down to this if necessary: case Response(302, _) => println("It moved") } ``` and also which would also allow my REST code to directly use and return: ``` Response(code, Body(contentType, content)) ``` which is easier to build a response dynamically. so... I can get it to compile (with deprecation warnings) via: ``` case class OK(override val body: Body) extends Response(200, body) ``` However, this doesn't seem to work with pattern matching. ``` Response(200, Body("application/json", "")) match { case OK(_) => ":-)" case _ => ":-(" } res0: java.lang.String = :-( ``` Any ideas on how this could work? I'm open to different approaches, but this was my attempt to find a practical use for case classes