I'm novice in Scala. Recently I was writing a hobby app and caught myself trying to use pattern matching instead of if-else in many cases.
user.password == enteredPassword match {
case true => println("User is authenticated")
case false => println("Entered password is invalid")
}
instead of
if(user.password == enteredPassword)
println("User is authenticated")
else
println("Entered password is invalid")
Are these approaches equal? Is one of them more preferrable than another for some reason?
class MatchVsIf {
def i(b: Boolean) = if (b) 5 else 4
def m(b: Boolean) = b match { case true => 5; case false => 4 }
}
I'm not sure why you'd want to use the longer and clunkier second version.
scala> :javap -cp MatchVsIf
Compiled from "<console>"
public class MatchVsIf extends java.lang.Object implements scala.ScalaObject{
public int i(boolean);
Code:
0: iload_1
1: ifeq 8
4: iconst_5
5: goto 9
8: iconst_4
9: ireturn
public int m(boolean);
Code:
0: iload_1
1: istore_2
2: iload_2
3: iconst_1
4: if_icmpne 11
7: iconst_5
8: goto 17
11: iload_2
12: iconst_0
13: if_icmpne 18
16: iconst_4
17: ireturn
18: new #14; //class scala/MatchError
21: dup
22: iload_2
23: invokestatic #20; //Method scala/runtime/BoxesRunTime.boxToBoolean:(Z)Ljava/lang/Boolean;
26: invokespecial #24; //Method scala/MatchError."<init>":(Ljava/lang/Object;)V
29: athrow
And that's a lot more bytecode for the match also. It's fairly efficient even so (there's no boxing unless the match throws an error, which can't happen here), but for compactness and performance one should favor if/else. If the clarity of your code is greatly improved by using match, however, go ahead (except in those rare cases where you know performance is critical, and then you might want to compare the difference).
Don't pattern match on a single boolean; use an if-else.
Incidentally, the code is better written without duplicating println.
println(
if(user.password == enteredPassword)
"User is authenticated"
else
"Entered password is invalid"
)
One arguably better way would be to pattern match on the string directly, not on the result of the comparison, as it avoids "boolean blindness". http://existentialtype.wordpress.com/2011/03/15/boolean-blindness/
One downside is the need to use backquotes to protect the enteredPassword variable from being shadowed.
Basically, you should tend to avoid dealing with booleans as much as possible, as they don't convey any information at the type level.
user.password match {
case `enteredPassword` => Right(user)
case _ => Left("passwords don't match")
}
Both statements are equivalent in terms of code semantics. But it might be possible that the compiler creates more complicated (and thus inefficient) code in one case (the match).
Pattern matching is usually used to break apart more complicated constructs, like polymorphic expressions or deconstructing (unapplying) objects into their components. I would not advice to use it as a surrogate for a simple if-else statement - there's nothing wrong with if-else.
Note that you can use it as an expression in Scala. Thus you can write
val foo = if(bar.isEmpty) foobar else bar.foo
I apologize for the stupid example.
It's 2020, the Scala compiler generates far more efficient bytecode in the pattern matching case. The performance comments in the accepted answer are misleading in 2020.
The pattern match generated byte code gives a tough competition to if-else at times pattern matching wins giving much better and consistent results.
One can use pattern match or if-else based on the situation & simplicity.
But the pattern matching has poor performance conclusion is no longer valid.
You can try the following snippet and see the results:
def testMatch(password: String, enteredPassword: String) = {
val entering = System.nanoTime()
password == enteredPassword match {
case true => {
println(s"User is authenticated. Time taken to evaluate True in match : ${System.nanoTime() - entering}"
)
}
case false => {
println(s"Entered password is invalid. Time taken to evaluate false in match : ${System.nanoTime() - entering}"
)
}
}
}
testMatch("abc", "abc")
testMatch("abc", "def")
Pattern Match Results :
User is authenticated. Time taken to evaluate True in match : 1798
Entered password is invalid. Time taken to evaluate false in match : 3878
If else :
def testIf(password: String, enteredPassword: String) = {
val entering = System.nanoTime()
if (password == enteredPassword) {
println(
s"User is authenticated. Time taken to evaluate if : ${System.nanoTime() - entering}"
)
} else {
println(
s"Entered password is invalid.Time taken to evaluate else ${System.nanoTime() - entering}"
)
}
}
testIf("abc", "abc")
testIf("abc", "def")
If-else time results:
User is authenticated. Time taken to evaluate if : 65062652
Entered password is invalid.Time taken to evaluate else : 1809
PS: Since the numbers are at nano precision the results may not accurately match to the exact numbers but the argument on performance holds good.
For the large majority of code that isn't performance-sensitive, there are a lot of great reasons why you'd want to use pattern matching over if/else:
it enforces a common return value and type for each of your branches
in languages with exhaustiveness checks (like Scala), it forces you to explicitly consider all cases (and noop the ones you don't need)
it prevents early returns, which become harder to reason if they cascade, grow in number, or the branches grow longer than the height of your screen (at which point they become invisible). Having an extra level of indentation will warn you you're inside a scope.
it can help you identify logic to pull out. In this case the code could have been rewritten and made more DRY, debuggable, and testable like this:
val errorMessage = user.password == enteredPassword match {
case true => "User is authenticated"
case false => "Entered password is invalid"
}
println(errorMesssage)
Here's an equivalent if/else block implementation:
var errorMessage = ""
if(user.password == enteredPassword)
errorMessage = "User is authenticated"
else
errorMessage = "Entered password is invalid"
println(errorMessage)
Yes, you can argue that for something as simple as a boolean check you can use an if-expression. But that's not relevant here and doesn't scale well to conditions with more than 2 branches.
If your higher concern is maintainability or readability, pattern matching is awesome and you should use it for even minor things!
I am here to offer a different opinion:
For the specific example you offer, the second one (if...else...) style is actually better because it is much easier to read.
In fact, if you put your first example into IntelliJ, it will suggest you to change to the second (if...else...) style. Here is the IntelliJ style suggestion:
Trivial match can be simplified less... (⌘F1)
Suggests to replace trivial pattern match on a boolean expression with a conditional statement.
Before:
bool match {
case true => ???
case false => ???
}
After:
if (bool) {
???
} else {
???
}
I'v came across same question, and had written tests:
def factorial(x: Int): Int = {
def loop(acc: Int, c: Int): Int = {
c match {
case 0 => acc
case _ => loop(acc * c, c - 1)
}
}
loop(1, x)
}
def factorialIf(x: Int): Int = {
def loop(acc: Int, c: Int): Int =
if (c == 0) acc else loop(acc * c, c - 1)
loop(1, x)
}
def measure(e: (Int) => Int, arg:Int, numIters: Int): Long = {
def loop(max: Int): Unit = {
if (max == 0)
return
else {
val x = e(arg)
loop(max-1)
}
}
val startMatch = System.currentTimeMillis()
loop(numIters)
System.currentTimeMillis() - startMatch
}
val timeIf = measure(factorialIf, 1000,1000000)
val timeMatch = measure(factorial, 1000,1000000)
timeIf : Long = 22
timeMatch : Long = 1092
In my environment (scala 2.12 and java 8) I get different results. Match performs consistently better in the code above:
timeIf: Long = 249
timeMatch: Long = 68
Related
This is my code:
package net.claritysales.api.helper
import net.claritysales.api.models.UserEntity
import scala.util.Random
trait TestData {
def userInfo(
id : Long = randomLong(),
username : String = randomString(),
password : String = randomString()
) : UserEntity = {
var user : UserEntity = new UserEntity(
id = id, //Error is Long and recived Optional[Long]
username = username,
password = password)
return user}
def randomString(): String = Random.alphanumeric.take(10).mkString("")
def randomLong(): Long = Random.nextLong()
}
and UserEntity:
case class UserEntity(id: Option[Long] = None, username: String, password: String) {
require(!username.isEmpty, "username.empty")
}
and the error message: Type mismatch, expected: Option[Long], actual: Long
How do I transform Optional[Long] to Long ? Id is Optiona[Long] randomLong() and id must is Long. Thanks!
I'm not sure where exactly the issue in your code is, but I'll cover the usual ways to deal with Option. Option solves the same problem that Java's null solves, but it does so in a way that is orders of magnitude better, safer, and easier to work with. So I'm going to work with a hypothetical function here, that just received a Option[A]. The question you need to ask yourself is: what does it mean if I get a None? Scala forces you to ask this question, where making all class types implicitly nullable (as in Java) does not.
Option 1: Propagate the Error Quietly
Perhaps None indicates a failure in the place where we got the A from. Something went wrong, the random generator failed, maybe we divided by zero. Then we want to indicate that we failed. So, in this case, we change our function's return type from A to Option[A] and return a None.
In Java, this would look like this.
if (arg == null)
return null;
return doSomething(arg);
In Scala,
arg map { x => doSomething(x) }
If arg is None, then this returns None. If arg contains a value, it runs doSomething on the value and returns the result, inside an Option[A].
Option 2: None indicates Different Behavior
Perhaps None indicates, in some sense, that we want the function to behave differently. In Java, this would look something like this.
if (arg != null) {
return doSomething(arg);
} else {
return doSomethingElse();
}
In Scala, we do this in a typesafe way.
arg match {
case None => doSomethingElse()
case Some(x) => doSomething(x) // Note that x is A, not Option[A]
}
Option 3: None is Just a Default
Sometimes None just indicates that we want to use a default value. If we're adding up a bunch of numbers, and some of them might be None, we want None to equate to the numerical value 0 so that it doesn't alter our results.
In Java, we might write,
int x = 0;
if (arg != null)
x = arg;
return doSomething(x);
In Scala, we can do this more concisely with getOrElse.
doSomething(arg.getOrElse(0))
Option 4: Propagate the Error Loudly
Maybe None is really bad in our case. Perhaps it's an error in the invoked code that we're just not at all equipped to handle. Perhaps our function is just waaaay too important, and if it fails then everything else is forfeit. Then we can raise an exception. Note that this approach is not very idiomatic in Scala, so it should be used very sparingly, only when it doesn't make sense to do any of the above.
In Java,
if (arg == null)
throw new RuntimeException("Oops!");
return doSomething(arg);
In Scala,
arg match {
case None => sys.error("Oops!")
case x => doSomething(x)
}
The problem isn't that you have an Option[Int] and need an Int (as you've claimed in the title and body of your question). It's that you have an Int and need an Option[Int]. This is because userInfo takes an Int, but UserEntity takes an Option[Int].
To solve this problem, you can simply pass Some(id) as the argument.
Use get or else, i dont know in your case what give in None case
var user : UserEntity = new UserEntity(
id = id.getOrElse(0l)
username = username,
password = password)
return user}
In Effective Scala article by Twitter, they say the following:
Use returns to clarify and enhance readability, but not as you would
in an imperative language; avoid using them to return the results of a
computation. Instead of
def suffix(i: Int) = {
if (i == 1) return "st"
else if (i == 2) return "nd"
else if (i == 3) return "rd"
else return "th"
}
prefer:
def suffix(i: Int) =
if (i == 1) "st"
else if (i == 2) "nd"
else if (i == 3) "rd"
else "th"
but using a match expression is superior to either:
def suffix(i: Int) = i match {
case 1 => "st"
case 2 => "nd"
case 3 => "rd"
case _ => "th"
}
In this specific example, why is match expression superior compared to the if/else?
In general match is more readable and explains your intention more clearly. But in this exact example, it has an added benefit, that match will emit not a series of ifs, but a switch bytecode instruction (the tableswitch one in this case), which is likely to improve performance a bit.
You can assert that in this case switch will be emitted with the #switch annotation:
def suffix(i: Int) = (i: #switch) match {
case 1 => "st"
case 2 => "nd"
case 3 => "rd"
case _ => "th"
}
Essential in pattern matching is data type extraction. For examples and discussion see for instance Extractor Objects and The Neophyte's Guide to Scala Part 1: Extractors.
In the examples above the data type proves trivial and the benefit may come chiefly from readability.
I'm fairly new to scala from java and also pretty new to pattern matching. One of the things I'm trying to get my head around is when to use it and what it's costs/benefits are. For example this
def myThing(a: Int): Int = a match {
case a: Int if a > 0 => a
case _ => myThing(a + 1)
}
Does the same thing as this (unless I've really misunderstood something)
def myThing(a: Int): Int = {
if (a > 0) a
else myThing(a + 1)
}
So my actual question:
But do they run the same way? Is my pattern matched example tail recursive? And if not, then why not when it is in the second example?
Are there any other things I should worry about, like resources? Or should I pretty much always try to use pattern matching?
I've searched around for these answers but haven't found any "best practices" for this!
Edit: I'm aware that the example used is a bit contrived - I've just added it to be clear about the question below it - thanks!
Yes they do run the same. Best practice for every syntactic sugar is the same: use it whenever it provides more readable or flexible code. In your examples in case of if statement you may omit braces and write just
def myThing(a: Int): Int = if (a > 0) a else myThing(a + 1)
Which is definitely more handy than pattern matching. Pattern matching is handy in situations where:
You have 3 or more alternatives
You should unpack\check values through extractors (check this question)
You should check the types
Also to ensure you function is tail-recursive you could use the #tailrec annotation
Another 'Scala' way to do it would be to define an extractor for a positive number
def myThing(a: Int): Int = a match {
case PositiveNum(positive) => positive
case negative => myThing(negative + 1)
}
object PositiveNum {
def unapply(n: Int): Option[Int] = if (n > 0) Some(n) else None
}
Yet another way to pattern-match against the evaluated predicate (condition),
def myThing(a: Int): Int = a > 0 match {
case true => a
case _ => myThing(a + 1)
}
where matches include no (additional) guards or type declarations.
One of the reasons why Scalaz Maybe was added was to get rid of get:
Some differences from std lib Option:
No unsafe get method
I understand get can be unsafe, but sometimes is is safe (in a code which has verified before the Option is not empty). There are some situations where one can easily stay away from using get, but sometimes it is not so obvious to me. What would be the alternatives to get in the following code?
def point(cursor:Int) : Option[XY]
def paste(cs: Seq[Int]) = {
if (validateSelection(cs)) {
cs.size match {
case 2 => // between two points
// editablePoint returning Option for general case,
// but here it is known to succeed as validateSelection passed
val beDiff = point(cs.head).get.xy - point(cs.last).get.xy
...
case _ =>
...
}
...
}
To get rid of the quasi-safe get, you have to refactor your validateSection. In your example it probably returns a Boolean:
def validateSection(cs: Seq[Int]): Boolean
Yet, you could return an evidence, that cs is valid:
/* Returns the first and last values of the sequence,
* if the sequence's length == 2. Otherwise `Empty`.
*/
def validateSection(cs: Seq[Int]): Maybe[(Int, Int)]
Then you could refactor your snippet as:
def paste(cs: Seq[Int]) = {
match validateSelection(cs) {
case (first, last) =>
val beDiff = first - last
...
case _ =>
...
}
...
}
EDIT You can take the idea further: Create auxillary types to get away of function's partiality.
The point returns Option[XY], i.e. it's partial. We should try to make input parameters more precise, so point can be total, i.e. return XY. Without knowing precise specification I can only sketch the solution:
case class Selection(/* ... */)
/* Constructed from `Selection` */
case class Cursor()
object Selection {
def first: Cursor = ???
def last: Cursor = ???
}
/* If `cs` is valid, we return a `ValidSelection`, othersise `Empty`. */
def validateSelection(cs: Seq[Int]): Maybe[Selection]
/* With more precise type, we can have total `point`. */
def point(cursor: Cursor): XY
This approach may look boilerplaty at first, but here we use the advantage of having the type system. Avoid stringly typed or List-typed programming.
I found myself writing something like this quite often:
a match {
case `b` => // do stuff
case _ => // do nothing
}
Is there a shorter way to check if some value matches a pattern? I mean, in this case I could just write if (a == b) // do stuff, but what if the pattern is more complex? Like when matching against a list or any pattern of arbitrary complexity. I'd like to be able to write something like this:
if (a matches b) // do stuff
I'm relatively new to Scala, so please pardon, if I'm missing something big :)
This is exactly why I wrote these functions, which are apparently impressively obscure since nobody has mentioned them.
scala> import PartialFunction._
import PartialFunction._
scala> cond("abc") { case "def" => true }
res0: Boolean = false
scala> condOpt("abc") { case x if x.length == 3 => x + x }
res1: Option[java.lang.String] = Some(abcabc)
scala> condOpt("abc") { case x if x.length == 4 => x + x }
res2: Option[java.lang.String] = None
The match operator in Scala is most powerful when used in functional style. This means, rather than "doing something" in the case statements, you would return a useful value. Here is an example for an imperative style:
var value:Int = 23
val command:String = ... // we get this from somewhere
command match {
case "duplicate" => value = value * 2
case "negate" => value = -value
case "increment" => value = value + 1
// etc.
case _ => // do nothing
}
println("Result: " + value)
It is very understandable that the "do nothing" above hurts a little, because it seems superflous. However, this is due to the fact that the above is written in imperative style. While constructs like these may sometimes be necessary, in many cases you can refactor your code to functional style:
val value:Int = 23
val command:String = ... // we get this from somewhere
val result:Int = command match {
case "duplicate" => value * 2
case "negate" => -value
case "increment" => value + 1
// etc.
case _ => value
}
println("Result: " + result)
In this case, you use the whole match statement as a value that you can, for example, assign to a variable. And it is also much more obvious that the match statement must return a value in any case; if the last case would be missing, the compiler could not just make something up.
It is a question of taste, but some developers consider this style to be more transparent and easier to handle in more real-world examples. I would bet that the inventors of the Scala programming language had a more functional use in mind for match, and indeed the if statement makes more sense if you only need to decide whether or not a certain action needs to be taken. (On the other hand, you can also use if in the functional way, because it also has a return value...)
This might help:
class Matches(m: Any) {
def matches[R](f: PartialFunction[Any, R]) { if (f.isDefinedAt(m)) f(m) }
}
implicit def any2matches(m: Any) = new Matches(m)
scala> 'c' matches { case x: Int => println("Int") }
scala> 2 matches { case x: Int => println("Int") }
Int
Now, some explanation on the general nature of the problem.
Where may a match happen?
There are three places where pattern matching might happen: val, case and for. The rules for them are:
// throws an exception if it fails
val pattern = value
// filters for pattern, but pattern cannot be "identifier: Type",
// though that can be replaced by "id1 # (id2: Type)" for the same effect
for (pattern <- object providing map/flatMap/filter/withFilter/foreach) ...
// throws an exception if none of the cases match
value match { case ... => ... }
There is, however, another situation where case might appear, which is function and partial function literals. For example:
val f: Any => Unit = { case i: Int => println(i) }
val pf: PartialFunction[Any, Unit] = { case i: Int => println(i) }
Both functions and partial functions will throw an exception if called with an argument that doesn't match any of the case statements. However, partial functions also provide a method called isDefinedAt which can test whether a match can be made or not, as well as a method called lift, which will turn a PartialFunction[T, R] into a Function[T, Option[R]], which means non-matching values will result in None instead of throwing an exception.
What is a match?
A match is a combination of many different tests:
// assign anything to x
case x
// only accepts values of type X
case x: X
// only accepts values matches by pattern
case x # pattern
// only accepts a value equal to the value X (upper case here makes a difference)
case X
// only accepts a value equal to the value of x
case `x`
// only accept a tuple of the same arity
case (x, y, ..., z)
// only accepts if extractor(value) returns true of Some(Seq()) (some empty sequence)
case extractor()
// only accepts if extractor(value) returns Some something
case extractor(x)
// only accepts if extractor(value) returns Some Seq or Tuple of the same arity
case extractor(x, y, ..., z)
// only accepts if extractor(value) returns Some Tuple2 or Some Seq with arity 2
case x extractor y
// accepts if any of the patterns is accepted (patterns may not contain assignable identifiers)
case x | y | ... | z
Now, extractors are the methods unapply or unapplySeq, the first returning Boolean or Option[T], and the second returning Option[Seq[T]], where None means no match is made, and Some(result) will try to match result as described above.
So there are all kinds of syntactic alternatives here, which just aren't possible without the use of one of the three constructions where pattern matches may happen. You may able to emulate some of the features, like value equality and extractors, but not all of them.
Patterns can also be used in for expressions. Your code sample
a match {
case b => // do stuff
case _ => // do nothing
}
can then be expressed as
for(b <- Some(a)) //do stuff
The trick is to wrap a to make it a valid enumerator. E.g. List(a) would also work, but I think Some(a) is closest to your intended meaning.
The best I can come up with is this:
def matches[A](a:A)(f:PartialFunction[A, Unit]) = f.isDefinedAt(a)
if (matches(a){case ... =>}) {
//do stuff
}
This won't win you any style points though.
Kim's answer can be “improved” to better match your requirement:
class AnyWrapper[A](wrapped: A) {
def matches(f: PartialFunction[A, Unit]) = f.isDefinedAt(wrapped)
}
implicit def any2wrapper[A](wrapped: A) = new AnyWrapper(wrapped)
then:
val a = "a" :: Nil
if (a matches { case "a" :: Nil => }) {
println("match")
}
I wouldn't do it, however. The => }) { sequence is really ugly here, and the whole code looks much less clear than a normal match. Plus, you get the compile-time overhead of looking up the implicit conversion, and the run-time overhead of wrapping the match in a PartialFunction (not counting the conflicts you could get with other, already defined matches methods, like the one in String).
To look a little bit better (and be less verbose), you could add this def to AnyWrapper:
def ifMatch(f: PartialFunction[A, Unit]): Unit = if (f.isDefinedAt(wrapped)) f(wrapped)
and use it like this:
a ifMatch { case "a" :: Nil => println("match") }
which saves you your case _ => line, but requires double braces if you want a block instead of a single statement... Not so nice.
Note that this construct is not really in the spirit of functional programming, as it can only be used to execute something that has side effects. We can't easily use it to return a value (therefore the Unit return value), as the function is partial — we'd need a default value, or we could return an Option instance. But here again, we would probably unwrap it with a match, so we'd gain nothing.
Frankly, you're better off getting used to seeing and using those match frequently, and moving away from this kind of imperative-style constructs (following Madoc's nice explanation).