Using a scala extractor as a parser - scala

I keep coming across situations where I want to use extractors as parsers, they are really useful for this but it never looks right, often the unapply looks like it should be an apply. Also, the parsing extractor may get in the way of the default extractor. Are there any patterns for this?
case class AnID(int: Int) extends AnyVal
object AnID {
def unapply(idString: String): Option[AnID] = "id-([0-9]+)".r match {
case Seq(intString: String) => Try(Integer.parseInt(intString)).map(AnID.apply).toOption
case _ => None
}
}
And a test:
AnID(8) should be (AnID(8))
val AnID(id1) = "id-1"
id1 should be (AnID(1))
val AnID(id2) = AnID(2)
id2 should be (2)
It is kind of strange.

You can create a Parse object inside the companion object to make it more clear that you're parsing.
case class AnID(int: Int) extends AnyVal
object AnID {
private val Reg = "id-([0-9]+)".r
object Parse {
def unapply(s: String): Option[AnID] = s match {
case Reg(digits) => Some(new AnID(digits.toInt))
case _ => None
}
}
}
So now you at least don't clobber your normal extractor and have things that look like val AnID.Parse(id) = "id-9".
Maybe that won't solve your general unease with pattern matching looking kind of backwards. If not, you can always make Parse just implement an apply, and then you get val Option(x) = AnID.Parse("id-9").

Related

Iterate through parameters and optional values in a case class checking that only certain fields are defined

I have a case class like the following except it has far more parameters (all optional):
case class MyClass(i: Option[String], j: Option[Int], n: Option[OtherClass])
I want to loop over the parameters and verify that only i and j are defined, while the rest are None. If the case class changes in the future I want to keep the same validation in place, which is why I am not using pattern matching or explicitly checking.
What is a good a way of doing this in scala 2.12?
You could use productIterator as #Tim explains, however this smells kinda bad. If there is a special situation in which only MyClass(Some(_), Some(_), None) is valid, but MyClass(Some(_), Some(_), Some(_)) is not, it appears that these should be two distinct types rather than a "catchall" class with ad-hoc validation tackled on the side.
Consider something like this:
sealed trait Foo {
def i: Option[String]
def j: Option[Int]
def n: Option[OtherClass] = None
}
case class IJ(iVal: String, jVal: Int) extends Foo {
def i = Some(iVal)
def j = Some(jVal)
}
case class IJN(i: Option[String], j: Option[Int], nVal: OtherClass) extends Foo {
override def n = Some(nVal)
}
This way, you can simply check the type of the object you are dealing with to distinguish between the two situations:
foo match {
case x: IJ => "i and j are defined, but n is not"
case x: IJN => "N is defined, but i and j might not be"
}
You can do this using productIterator which is a list of fields for the case class:
def verify(mc: MyClass) = {
val c = mc.productIterator.count{
case o: Option[_] => o.nonEmpty
case _ => true
}
mc.i.nonEmpty && mc.j.nonEmpty && c == 2
}
However this kind of generic code has risks, so I would recommend avoiding a case class with a lot of fields. Consider grouping various fields into their own object and the making the test explicit on the known fields.
Updating the test when the number of fields changes is not a great chore, and is an opportunity to check that those changes have not affected your code.
Original version using method:
case class MyClass(i: Option[String], j: Option[Int], n: Option[OtherClass])
{
def verify = {
val c = this.productIterator.count{
case o: Option[_] => o.nonEmpty
case _ => true
}
i.nonEmpty && j.nonEmpty && c == 2
}
}
I figured out you can do this through reflection, although it may not be recommended see note below:
val allowableFieldNames = Set("i", "j")
val fields = universe.typeOf[MyClass].decls.collect {
case m: MethodSymbol if m.isCaseAccessor => m.name.toString
}.toList
val values = myClass.productIterator.toList
values.zip(fields).collect {
case(o: Option[_], field: String) if !allowableFieldNames(field) => assert(o.isEmpty)
}
This is assuming that productIterator and universe.typeOf[].decls return the parameters and their values in the same order.
From #Dima:
Reflection is a kind of a "meta-tool" you resort to (generally, when creating low-level libraries) for a specific reason, to address a specific issue that scala standard toolset does not provide for.

Can't access extra methods of trait implementation

Please take a look at the following example:
trait MyTrait {
def myTraitMeth : String
}
object TraitImplementation extends MyTrait {
def myTraitMeth = "Works fine"
def myExtraMeth = "Doesn't work"
}
case object Manager {
def returnImplementation : MyTrait = TraitImplementation
}
println(Manager.returnImplementation.myExtraMeth)
In this scenario, what is happening is that I can't access the extra method of the trait implementation, TraitImplementation, because I defined the return method of the method returnImplementation to be of the type MyTrait - I cannot change this condition.
An obvious solution would be enforcing this extra method on the trait, but that is not an option for me, given the fact that other implementations of the MyTrait cannot have such a method.
What I really need is to make sure that the method returnImplementation will return something that is an implementation of MyTrait, and, at the same time, allow the caller of that method to use all methods that have been implemented, not only those enforced on the trait.
I tried messing around with types, going with something like
case object Manager {
def returnImplementation [A <: MyTrait] : A = TraitImplementation
}
but this leads to a type mismatch, because the compiler cannot understand that A is a generic type.
Any ideas on how to accomplish it?
I originally wanted to leave this as a comment, but there was a discussion going on so that the space was getting kind of crowded. I decided to write it up as an answer instead.
This problem you have sounds like something you would get around by using case matching. When returnImplementation returns a trait of type MyTrait, case match on it to get the desired subclass, and depending on which subclass it is, have different behavior. Wrap it in an Option if you want monadic fail-fast behavior, so that only certain subclass will trigger the creation of some result. The result will be Some(...) if the desired subclass with the desired method was found, None otherwise.
trait MyTrait {
def myTraitMeth : String
}
object TraitImplementation extends MyTrait {
def myTraitMeth = "Works fine"
def myExtraMeth = "Doesn't work"
}
case object Manager {
def returnImplementation : MyTrait = TraitImplementation
}
For your println statement, you would call it like so:
Manager.returnImplementation match {
case TraitImplementation => println(TraitImplementation.myExtraMeth)
case _ =>
}
If you want to keep your code purely functional with no side-effects like println functions, do the following:
val result = Manager.returnImplementation match {
case TraitImplementation => Some(TraitImplementation)
case _ => None
}
result will be of type Option[TraitImplementation] and you can pass it around for context dependent behavior.
If you have side effecting code, like your println statement, you can isolate it from the rest of your purely function code by calling foreach on this Option like so:
result.foreach(x => println(x.myExtraMeth))
Based on the discussion Luis and you had, you can also case match on MyExtTrait for the desired behavior.
trait MyExtTrait {
def myExtraMeth: String
}
val result = Manager.returnImplementation match {
case x: MyExtTrait => println(x.myExtraMeth)
case _ =>
}
or
val result = Manager.returnImplementation match {
case x: MyExtTrait => Some(x)
case _ => None
}
result.foreach(x => println(x.myExtraMeth))

Call .toDouble on Any and return Option[Double]

Curious if anyone has a creative approach for the following:
def toDouble(any: Any): Option[Double] = // { if any has a .toDouble method call it else return None }
For instance, Int, String, Long all have a .toDouble method. I'd like it to be called if it exist (even non primitive types).
Ideally something like this (without .toString'ing everything first)
def toDouble(any: Any): Option[Double] = {
case any.hasToDouble => Try(any.toDouble).toOption
case _ => None
}
You can use
def doubleFromAny(in: Any): Option[Double] = {
Try{in.asInstanceOf[{def toDouble: Double}].toDouble}.toOption
}
The problem with this is any toDouble provided through an implicit won't work (so the string "4.5" would give you None). I also expect performance would not be great.
In the end, you need to figure out what types are possible and use something like Jon Anderson's answer to check and cast each type.
You can use pattern matching. This has the additional benefit of giving you more explicit control over how the conversion is done. (Eg, if you wanted to try additional string parsing)
def toDouble(any: Any): Option[Double] = {
any match {
case n:Int => Some(n.toDouble)
case n:Long => Some(n.toDouble)
case n:Double => Some(n.toDouble)
case s:String => Try(s.toDouble).toOption
case _ => None
}
}
def toDouble(a: Any): Option[Double] = try {
if (a == null) None else {
Some(a.toString.toDouble)
}
} catch {
case scala.util.control.NonFatal(e) => None
}
Others have suggested good answers. Another way I thought of doing was using implicit object. For your above example you could write something like:
sealed trait ImplicitType[T]
object ImplicitType{
implicit object IntType extends ImplicitType[Int]
implicit object StringType extends ImplicitType[String]
implicit object LongType extends ImplicitType[Long]
implicit object DoubleType extends ImplicitType[Double]
}
def toDouble[T : ImplicitType](n: T) : Option[Double] = {
Try(n.toString.toDouble).toOption
}
The above works because, the compiler constraint is from the availability of implicit objects in ImplicitType companion object. The context bound implicit def f: ImplicitType[T] by default searches for implicit objects inside companion object of ImplicitType. So now you can do things like:
val foo = toDouble(1) // Some(1.0)
val foo1 = toDouble("2") //Some(2.0)
val foo2 = toDouble(1L) //Some(1.0)
val foo3 = toDouble("s") //None
val foo4 = toDouble(1.23456e300d) //Some(1.23456E300)
In this way your toDouble function does not change at all. I couldn't think of a way to avoid toString sorry. Hope this works for you.

How to extend String to add new unapply function for using it in extracting?

I want to use a Scala extractor to match my custom type with a String (in that specific order, not String to Scala). Here is my code:
class Scala
object Scala {
def apply(s: String) = new Scala
def unapply(sc: Scala) = Some("Scala")
}
class ExtendedString(s: String) {
def unapply(sc: Scala): Option[String] = {
Some(s)
}
}
implicit def str2Scala(s: String): ExtendedString = {
new ExtendedString(s)
}
Scala match {
case "abc" => println("Aha!")
case "def" => println("Yeah!")
case "scala" => println("Scala!")
}
But it does not work. I get an error:
Error:(20, 9) type mismatch;
found : String("abc")
required: A$A109.this.Scala.type
case "abc" => println("Aha!")
^
How can I fix it to make extractor work?
PS
My original idea was to provide an implicit converter to extend String class with ExtendedString class and then to implement unapply method there to make extraction possible.
There should be no need whatsoever for implicits if all you want is an extractor.
To define an extractor, you make an object with an unapply method. E.g.
object MyExtractor {
def unapply(value: ValueBeingMatched): Option[ExtractedValue] = { ... }
}
Then you match a value using the extractor
val myValue: ValueBeingMatched = ...
myValue match {
case MyExtractor(extractedValue) => println(s"I got $extractedValue!")
}
If you want your extractor to come back with multiple values, the unapply should return an option of tuple:
object MyExtractor {
def unapply(value: ValueBeingMatched): Option[(ResultType1, ResultType2, ...)] = { ... }
}
val myValue: ValueBeingMatched = ...
myValue match {
case MyExtractor(result1, result2, ...) => ...
}
I'm not clear on what you are trying to accomplish from your example code, so I'll make an example that maybe is relevant for you.
Let's say you make a custom Point class:
case class Point(x: Int, y: Int)
And you want to be able to extract points from a String. In this case, the ValueBeingMatched is a String, and the ExtractedValue is a Point. I'll also define the extractor in the Point object. As for functionality, let's assume that a string like "12,8" corresponds to a Point(12, 8).
object Point {
def unapply(s: String): Option[Point] = {
val parts = s.split(",")
// this is just example code, so I won't handle failures,
// but if it did fail, you'd return a None instead of Some
Some(Point(parts(0).toInt, parts(1).toInt))
}
}
Now that it's defined, you can match strings using the Point extractor:
val s = "3,4"
s match {
case Point(p) => // p is actually an instance of Point
}
edit to respond to feedback:
In order to match directly to a string, the value being matched must already be a String. So one way would be to add a converter method e.g.
instanceOfMyType.convertToString match {
case "abc" => println("Aha!")
}
Or you would have to write an extractor to allow
instanceOfMyType match {
case Extracted("abc") => println("Aha!")
}

Overriding arithmetic operators on Int via implicit conversions

Say that, for aesthetical reasons, I want to be able to write:
3 / 4
and have / be a method on a class that there exists an implicit conversion from Int to, e.g.:
class Foo(val i: Int) {
def /(that: Int) = // something
}
implicit def intToFoo(i: Int) = new Foo(i)
Is this at all possible, i.e. is it possible to "disable" the / method on Int?
In short: No, you can't.
Implicit resolution will only take place if you attempt to call a method that doesn't already exist.
A more "idiomatic" solution would be to create your own pseudo-number type, something like:
case class Rational(a: Int, b: Int) {
// other methods
}
val foo = Rational(3, 4)
or
case class Path(value: String) {
def /(other: String): Path = ...
}
val p = Path("3") / "4"
Is there a reason that something like
trait PathElement[T] { val value: T }
case class IntElement(value: Int) extends PathElement[Int]
case class StringElement(value: String) extends PathElement[String]
case class Path(parts: Seq[PathElement[_]]) {
def /(other: Path): Path = copy(parts = parts ++ other.parts)
}
object Path {
def apply(part: PathElement[_]): Path = Path(List(part))
implicit def int2path(i: Int): Path = Path(IntElement(i))
implicit def str2path(s: String): Path = Path(StringElement(s))
}
wouldn't work for you? This would allow you to write, for example,
import Path._
"foo" / 3 / 4 / "bar"
This works because String does not have its own / method, so the first "foo" is implicitly converted to a Path. If you were starting a Path with an Int, you'd have to convert it explicitly, but you'd get any other Ints for free.
I can of course only guess what you really want to accomplish but I assume you don’t just want to match concrete URLs but also extract information from given strings. E.g. when given "/foo/21" you don’t just want to know that this matches some "foo" / 21 but you want to do something with the value of 21.
I’ve found the URI matching process in Lift to be quite useful, so maybe that fits your use case. (I’m using a very simplified version, of course.) It’s done with Lists there which makes matching a little easier but it also means you’ll have to use :: instead of /.
But that’s not the point: what I want to show is the advantage of not using implicit conversions and the power of extractors
object AsInt {
def unapply(i: String): Option[Int] = try {
Some(i.toInt)
} catch {
case e: java.lang.NumberFormatException => None
}
}
def matchUrl(url: String) = {
val req:List[String] = url.split('/').toList.drop(1)
req match {
case "foo" :: "bar" :: Nil => println("bar")
case "foo" :: AsInt(i) :: Nil => println("The square is " + i*i)
case "foo" :: s :: Nil => println("No int")
case _ => println("fail")
}
}
matchUrl("/foo/21")
matchUrl("/foo/b")
matchUrl("/foo/bar")
matchUrl("/foobar")
// prints:
// The square is 441
// No int
// bar
// fail
In short, using the AsInt extractor instead of an implicit conversion of Int to String you can actually retrieve the integer value from the string if and only if it is convertible and of course use it immediately. Obviously, if you don’t like the naming, you can change it to something more unobtrusive but if you really want to do url matching, you maybe should not convert everything implicitly.