Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - add unapply to Int

I want to be able to do this:

scala> val Int(i) = "1"
i: Int = 1

But Int doesn't have an unapply method.

I found this answer which gives instructions on how to implicitly add a method to an existing object, so I tried it out. The solution they gave works, but unfortunately not for pattern matching. Here's what I have:

object UnapplyInt {
  val IntRE = """^(\d+)$""".r
  def unapply(v: String): Option[Int] = v match {
    case IntRE(s) => Some(s.toInt)
    case _ => None
  }
}
implicit def int2unapplyInt(objA: Int.type) = UnapplyInt

These test cases are all fine:

val UnapplyInt(i) = "1"       // pattern matching with unapply is fine
val i = Int.unapply("1").get  // implicit conversion is fine

But the one I want fails:

scala> val Int(i) = "1"
<console>:10: error: object Int is not a case class constructor, nor does it have an unapply/unapplySeq method
       val Int(i) = "1"
           ^

If the implicit conversion works and pattern matching with unapply works, why doesn't Scala put these two things together for implicit pattern matching?

like image 298
dhg Avatar asked Mar 15 '12 19:03

dhg


1 Answers

edit So my original reasoning was no good. The real reason is from Section 8.1.8 of the Scala language spec

Syntax:
    SimplePattern ::= StableId ‘(’ [Patterns] ‘)’

That is, the extractor object has to be stable, and an implicit conversion is not stable. No explanation is given for why the extractor must be stable; I suspect it is because Scala does not want to treat the extractor as an expression because that could quickly become ambiguous:

... match {
    foo(bar)(baz)
}

Now which is the constructor and which are the pattern variables?

Luckily you can do this and it works just fine (though, as you commented, introduces other problems):

object Int {
    def unapply(v: String) = try Some(v.toInt)
        catch { case _: NumberFormatException => None }
}

val Int(i) = "5"

since the type Int and the object Int are in different namespaces.

like image 145
Owen Avatar answered Oct 21 '22 23:10

Owen