4
votes

I have an extractor which extracts an object from a string.

case class ItemStructure(id: String, data: String)
object ItemStructure {
  def unapply(str: String): Option[ItemStructure] = {
    str.split('-').toList match {
      case List(id, data) => Some(ItemStructure(id, data))
      case _              => None
    }
  }
}

If I try to use this extractor in a pattern matching, then all works as expected.

"" match {
  case ItemStructure(item) =>
}

It also works in a pattern matching anonymous function.

Option("").map {
  case ItemStructure(item) => 
}

Now, if I try to use this extractor in a partial function, the compiler fails with the message: cannot resolve overloaded unapply

val func: PartialFunction[Any, Unit] = {
  case ItemStructure(item) =>
}  

If I rename the companion object where the unapply function is located then all works as expected.

Could someone explain why the extract doesn't work if it's located in the companion object?

2

2 Answers

4
votes

There are two ItemStructure.unapply methods: The one created by the case class and the one you created yourself. The former takes an argument of type ItemStructure and the latter takes an argument of type String.

In your first two examples the type of the matched object is String, so only the second unapply method can be applied and there's no ambiguity. But in the last example both unapply methods would qualify, so Scala does not know which one to use.

If you put your unapply method somewhere else than the companion object, there's no longer two unapply methods - only yours (because the other one still lives in the companion object). So that resolves the ambiguity: ItemStructure.unapply clearly refers to the auto-generated unapply and NewName.unapply clearly refers to your.

2
votes

With Any as result type Compiler is not able to figure out where should it take the unapply function from. Your unapply defines only behaviour for String type.

This would work though:

val func: PartialFunction[String, Unit] = {
  case ItemStructure(item) =>
} 

Otherwise try defining unapply function that takes the type Any.