Pattern matching using current object - scala

I'm trying to match an Option, and test to see if it's a Some containing the object making the call. So the code I want to write looks like this:
methodReturningOption() match {
case Some(this) => doSomething()
case _ => doSomethingElse()
}
but that fails to compile, with the error
'.' expected but ')' found
I also tried using Some(`this`) which gives the error
not found: value this
I can make it work if I add a variable which refers to this
val This = this
methodReturningOption() match {
case Some(This) => doSomething()
case _ => doSomethingElse()
}
but that looks ugly and seems like an unpleasant workaround. Is there an easier way to pattern match with this as an argument?

I suppose you could try this:
methodReturningOption() match {
case Some(x) if x == this => doSomething()
case _ => doSomethingElse()
}

It looks like this is considered a special keyword and can't be used in that context.
Jack Leow's solution is probably the best - I'd recommend going with that since it's much more explicit. However as an alternative you can also create a variable point to 'this' using the following syntax. (Note the self => on the first line)
class Person { self =>
def bla() = methodReturningOption() match {
case Some(`self`) => ???
case _ => ???
}
}
This doesn't really answer the question, it's just a potential alternative syntax that may be useful to you.

Related

Scala patternmatching: do nothing for some cases

I have to perform some actions based on cases in a pattern matching block, but only for selective cases, and nothing to be done for remaining. So is it ok to just return () for remaining cases? Something like this:
val x = ....
val y = ....
(x, y) match {
case (Some(number), Some(text)) => {
......
}
case (Some(number), None) => {
......
}
case (_, _) => () // do nothing
}
Depends what you mean by "ok". If you are asking if it will compile, you can easily answer that question yourself, by running a few snippets in a REPL and find out, that you don't even need to return a unit. Something like this works just fine:
"foo" match {
"bar" => "baz"
"bat" => 1500
_ =>
}
If however by "ok" you meant whether it is a good idea, then the answer is "probably not". As mentioned in the comments, this is not type-safe and also purely side-effecting and not referentially transparent. There is likely a better way to do what you want.
It's generally ok, if all the cases in a match result in Unit (spelled () in Scala), to have a case result in () to preserve exhaustivity.
That said, in this case, where you require the first Option to be defined to do anything, I would probably express this as:
x.foreach { number =>
y match {
case Some(text) =>
??? // note that { } aren't required in match and ??? is idiomatic for "some code here"
case None =>
???
}
}
Then again, I particularly dislike pattern matching on Option, so ymmv.

How to use a Result[String] in Scala match expression

In the following code the first expression returns a Result[String] which contains one of the strings "medical", "dental" or "pharmacy" inside of a Result. I can add .toOption.get to the end of the val statement to get the String, but is there a better way to use the Result? Without the .toOption.get, the code will not compile.
val service = element("h2").containingAnywhere("claim details").fullText()
service match {
case "medical" => extractMedicalClaim
case "dental" => extractDentalClaim
case "pharmacy" => extractPharmacyClaim
}
Hard to say without knowing what Result is. If it's a case class, with the target String as part of its constructor, then you could pattern match directly.
Something like this.
service match {
case Result("medical") => extractMedicalClaim
case Result("dental") => extractDentalClaim
case Result("pharmacy") => extractPharmacyClaim
case _ => // default result
}
If the Result class doesn't have an extractor (the upapply() method) you might be able to add one just for this purpose.
I'm assuming this Result[T] class has a toOption method which returns an Option[T] - if that's the case, you can call toOption and match on that option:
val service = element("h2").containingAnywhere("claim details").fullText().toOption
service match {
case Some("medical") => extractMedicalClaim
case Some("dental") => extractDentalClaim
case Some("pharmacy") => extractPharmacyClaim
case None => // handle the case where the result was empty
}

Is there a way to match everything but a certain type (or set of types) without using isInstnaceOf?

I know that you can match a set of types like so, without using isInstanceOf:
x match {
case fooBar # (_: Foo | _: Bar) => ???
}
But, is there a way to match anything but a set of types? Like, match any x which is not a Foo or a Bar, without using isInstanceOf?
Well, you can do
x match {
case fooBar #(_: Foo | _: Bar) => // do nothing
default => // do something
}
Anyway, the only difference with using isInstanceOf is syntax, as you will be performing a runtime check nonetheless.
From a functional point of view, the combo isInstanceOf/asInstanceOf is identical to type matching.
So (if you really must) I would just go with
if (!(x.isInstanceOf[Foo] || x.isInstanceOf[Bar])) {
// do something
}
Again, there's no practical difference and they're both quite a hacky way of dealing with types. Unless you're working with an external API you have not control over, I would suggest to change your design and avoid matching on the types.
Usually type classes come in handy, but without further details it's hard to tell for sure.
The solution above by #GabrielePetronella work well for most cases, but I'm adding another variant that can help with some edge cases.
Edge case example:
composed Receive functions for akka actors.
consider the following:
override def receive: Receive = handleFoo orElse handleBar
def handleFoo: Receive = {
case FooObject => …
case FooClass(value) => …
case notFoo =>
logger.debug(s"wasn't expecting $notFoo of type ${notFoo.getClass.getSimpleName}")
}
def handleBar: Receive = {
case _: VeryImportantBarMsg => …
case _: LessImportantBarMsg => …
}
The last case of handleFoo will catch everything, making the orElse handleBar obsolete, and obviously we don't handle VeryImportantBarMsg or LessImportantBarMsg any more.
Solution:
use a specialized extractor object, e.g:
object NotBar {
def unapply[T](t: T): Option[T] = t match {
case _: VeryImportantBarMsg | _: LessImportantBarMsg => None
case _ => Some(t)
}
}
and use it like:
def handleFoo: Receive = {
case FooObject => …
case FooClass(value) => …
case NotBar(notFoo) =>
logger.debug(s"wasn't expecting $notFoo of type ${notFoo.getClass.getSimpleName}")
}
This solution is intended for case where you don't want the match to succeed, like partial functions, akka receive, or if you find yourself writing the same excluded list of types _: T1 | … | _: T10 many times, etc'...
P.S.
If you find yourself in need of this solution, most likely something isn't modeled optimally. In most cases, this can be avoided.

How to map an Option case class

Say, there is a case class
case class MyCaseClass(a: Int, b: String)
and an Option[MyCaseClass] variable
val myOption: Option[MyCaseClass] = someFunctionReturnOption()
Now, I want to map this Option variable like this:
myOption map {
case MyCaseClass(a, b) => do some thing
}
It seems the compiler reports error like It needs Option[MyCaseClass], BUT I gave her MyCaseClass, bla bla... How to use pattern match in Optional case class ?
Consider extracting the Option value like this,
myOption map {
case Some(MyCaseClass(a, b)) => do some thing
case None => do something else
}
or else use collect for a partial function, like this
myOption collect {
case Some(MyCaseClass(a, b)) => do some thing
}
Update
Please note that as commented, the OP code is correct, this answer addresses strictly the last question How to use pattern match in Optional case class ?
MyOption match {
Some(class) => // do something
None => // do something.
}
Or
MyOption map (class =>//do something)

Scala pattern matching case is skipped

Thanks for the excellent example, I tried it and it works as I expected. Nice to see someone understood the nature of the problem. However, I think I should have tagged the problem with Lift as I'm using the Lift framework and that is where this problem is (still) occurring (although I still think it might be related to extraction in scala). Since I don't want to reproduce the entire Lift setup here as it will be too much code, I'm going to hope someone familiar with Lift can understand what I'm doing here. I've removed more variables so it might be easier (for some) to see the problem:
lazy val dispatch: LiftRules.DispatchPF = {
// Explicitly setting guard to false to trigger the scenario
case req: Req if false => () => println("shouldn't match"); Empty
// This should match since previous case will never match
case Req(_, _, _) => () => println("should match"); Empty
// This is actually called...
case _ => () => println("shouldn't reach here"); Empty
}
As before, if I comment out the first case the second case is matched as expected.
For those interested, a simple workaround is:
lazy val dispatch: LiftRules.DispatchPF = {
case req: Req => {
if (false) { // Obviously you put something more useful than false here...
() => println("shouldn't match"); Empty
} else req match {
// This matches
case Req(_, _, _) => () => println("should match"); Empty
// This is now never called
case other => () => println("shouldn't reach here"); Empty
}
}
}
ORIGINAL POST
I'm new to scala, so I may be doing something wrong here, but I have a pattern matching expression that seems to be skipped over. Here's the code:
lazy val dispatch: LiftRules.DispatchPF = {
// Explicitly setting guard to false to trigger the scenario
case req: Req if false => () => Full(...)
// This should match since previous case will never match
case Req("api" :: "test" :: Nil, suffix, GetRequest) => () => Full(...)
// This is actually called...
case _ => () => println("not sure what's going on"); Empty
}
If I take out the first case expression, everything works as expected. I'm tempted to think this is a bug (https://issues.scala-lang.org/browse/SI-2337), but does anyone know of a workaround?
At the very least, change the last line:
case other => () => { println("not sure what's going on " + other); Empty }
and tell us what it prints
I just typed up an example which seems to be the same scenario you've got in your code, and it works as expected in Scala 2.9:
case class Foo(x:String)
val bar = Foo("bar")
bar match {
case x:Foo if false => println("Impossible")
case Foo(x) => println("Expected: " + x)
case _ => println("Should not happen")
}
Which outputs Expected: bar
See if you can reproduce the bug in a self-contained example like this, so maybe we (or if it is a bug, the Scala Dev Team, can figure out what is going wrong :)
Note: Seems like I misread your question the first time, sorry for that. I'm not going to delete this part anyway, because it might be helpful to someone else.
When using pattern matching, the first case-statement that matches will be executed, and after that, the match is complete and all other case statements will be ignored!
Your problem here is, that the first statement
case req:Req =>
matches every instance of Req. After matching the first statement and executing its code, Scala just jumps out of the match expression because it is finished. The second case-statement would match, but it is never executed for any given instance of Req because the first one matches. As far as I remember, this is known as shadowing a case statement.
So move your second case statement before the first one, and you should be fine.
Note that this is why in pattern matching, the more specific match cases need to come first and the more general case statements have to go last.
This is indeed the bug you are referencing in the Scala bug tracker. Req is a non-case class with a companion extractor methods, so the bug manifests itself here. The workaround you introduced seems fine.
For those interested, here is a sample case where the bug manifests itself:
class Sample(val a: String)
object Sample {
def apply(a: String) = new Sample(a)
def unapply(s: Sample) = Option(s.a)
}
val s = new Sample("a")
val r = s match {
case n: Sample if false => "Wrong 1: " + n
case Sample(_) => "Yay"
case n => "Wrong 2: " + n
}
println("Found " + r)
assert(r == "Yay")