🌞


Note that this blog post has been archived. Information may be out of date or incorrect.

Multiple unapply methods for pattern matching in Scala

TLDR: Take my directly to the solution.

I found this nice trick on the Scala forums. Lets imagine we have a case class such as the following:

:scala:
case class Foo(a:String, b:String, c:String = null, d:String = null)

This case class, as you probably know, can now be “pattern matched” like this:

:scala:
Foo("foo", "bar", "baz", "wobble") match {
	case Foo("foo", b, _, _) => b
	case _ => "What?"
}

But what if, most of the time, you only need the first two arguments, and the others are mostly irrelevant for your pattern matching. You wouldn’t want to write Foo(a, _, _ ,_) all the time, right? One possibility would be to write the unapply(x:Foo) method yourself:

:scala:
class Foo(val a:String, val b:String, val c:String = null, val d:String = null)

object Foo {
	def unapply(x:Foo): Option[(String, String)] = Some(x.a, x.b)
}

new Foo("foo", "bar", "baz", "wobble") match {
	case Foo("foo", b) => b
	case _ => "What?"
}

But what if you would like to use both unapply methods at some point? In that case you have to define multiple objects with different unapply methods, because unfortunately, unlike apply, unapply can’t be overloaded (because it always takes the the same argument).

So here is my approach to multiple unapply methods:

:scala:
case class Foo(val a:String, val b:String, val c:String = null, val d:String = null)

object Foo_ {
	def unapply(x:Foo): Option[(String, String)] = Some(x.a, x.b)
}

new Foo("foo", "bar", "baz", "wobble") match {
	case Foo_("foo", b) => b
	case Foo(a, _, _, d) => (a, d)
	case _ => "What?"
}

While it isn’t exactly awesome because you have to introduce a new object Foo_, I like it better than always having to write out all 4 (or more) parameters.

If you have a better approach to this problem, please let me know :)