An implicit class is a correct way to add extension method to an object
implicit class IntOps(obj: Int.type) { def parse(s: String): Option[Int] = s.toIntOption } Int.parse("123") // Some(123)
And unapply can be added in the same way
implicit class IntOps(obj: Int.type) { def unapply(s: String): Option[Int] = s.toIntOption } Int.unapply("123") // Some(123)
Just this will have no impact on pattern matching
"123" match { case Int(i) => ??? // doesn't compile: object Int is not a case class, nor does it have a valid unapply/unapplySeq member }
The place where Scala 2 compiler throws object Int is not a case class, nor does it have a valid unapply/unapplySeq member is here: https://github.com/scala/scala/blob/v2.13.10/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala#L121-L122
else if (!reallyExists(member)) CaseClassConstructorError(fun, s"${fun.symbol} is not a case class, nor does it have a valid unapply/unapplySeq member")
This is based on symbols (kind of typeOf[Int.type].decl(TermName("unapply")) in scala-reflect terms). Implicit conversions (extension methods) are not checked here.
This is modified in Scala 3: https://github.com/lampepfl/dotty/blob/3.2.2/compiler/src/dotty/tools/dotc/typer/Applications.scala#L1291-L1341 The compiler tries to typecheck x.unapply and this includes implicit conversions.
By the way, when Scala 2 compiler decides whether to generate unapply in the companion object of a case class (Int wasn't a case class) the compiler doesn't check extension methods either
How can I view the code that Scala uses to automatically generate the apply function for case classes?
case class MyClass(i: Int) MyClass(42) match { case MyClass(i) => println(i) // 42 }
case class MyClass(i: Int) object MyClass { def unapply(mc: MyClass): Option[Int] = Some(100) } MyClass(42) match { case MyClass(i) => println(i) // 100 }
case class MyClass(i: Int) implicit class MyClassCompanionOps(mc: MyClass.type) { def unapply(mc: MyClass): Option[Int] = Some(100) } MyClass(42) match { case MyClass(i) => println(i) // 42 }
And this behavior is the same in Scala 3.
How to extend String to add new unapply function for using it in extracting?
enrich PartialFunction with unapply functionality
Int.typeis the right way to add extension methods to the companion object of the typeInt- It just seems you can't addunapplyas an extension in Scala 2.