These two statements behave the same :
def getNum(inp: String): Double = inp match { case "" | null => 0.0 case _ => inp.toDouble }
def getNum(inp: String): Double = inp match { case "" | null => 0.0 case x => x.toDouble }
Question is, where should either one be used and is one essentially better than the other?
The bytecode for the two is identical, so you can use whichever you prefer stylistically.
Note that in some cases you may have a complex expression as the source of your value to match, which makes it harder to refer to. Thus you may have greater consistency of style with the case x => x.toDouble form.
Related
I have been working with Scala for close to a year, but every now and then I come across a piece of code that I don't really understand. This time it is this one. I tried looking into documents on "scala methods with generic parameter type", but I am still confused.
def defaultCall[T](featureName : String) (block : => Option[T])(implicit name: String, list:Seq[String]) : Option[T] =
{
val value = block match {
case Some(n) => n match {
case i : Integer => /*-------Call another method----*/
case s : String => /*--------Call another method----*/
}
case _ => None
}
The method is called using the code shown below :
var exValue = Some(10)
val intialization = defaultCall[Integer]("StringName"){exValue}
What I don't understand in the above described code is the "case" statement in the defaultCall method.
I see that when the exValue has a value and is not empty, the code works as expected. But in case I change the exValue to None, then my code goes into the "case _ = None" condition. I don't understand why this happens since the match done here is against the "variable" which would be either an Integer or a String.
What happens here is that when you pass a None it will match on the second case, which "catches" everything that is not an instance of a Some[T]:
block match {
case Some(n) => // Will match when you pass an instance of Some[T]
case _ => // Will match on any other case
}
Note that None and Some are two different classes that inherit from Option.
Also, the variable match is only done if the first match succeeds, otherwise not. To achieve the type checking in the first match you could do:
block match {
case Some(n: Int) => // do stuff
case Some(n: String) => // do stuff
case _ => // Will match on any other case
}
Hope that helps
So I am creating a parser to parse some configuration files made by our client engineers. I don't particularly trust our client engineers. They can usually spell things right but they can never remember what to capitalize. This makes Enum classes kind of noisome in that they go and break the program cause the Enum fails if they don't type in the exact right string.
Here is my Enum Class:
object EnumLayoutAlignment extends Enumeration
{
type Alignment = Value
val Vertical = Value("Vertical")
val Horizontal = Value("Horizontal")
}
Is there a way I could make it so that "Vertical", "vertical", and "VERTICAL" all mapped to the same enum value?
EDIT: #Radai brought up a good point of just .upper() on the input but I would also like to include "vert" and other similar inputs
I used this as an example
One way to handle this is to provide a method for deserialization:
def fromString(s: String) = s.upper() match {
case "VERTICAL" | "VERT" | "V" => Some(Vertical)
case "HORIZONTAL" | "HORIZ" | "H" => Some(Horizontal)
case => None
}
Then using it is as simple as:
EnumLayoutAlignment.fromString(someInput).map(doThingWithValidEnum)
You can add a method like this to your Enumeration:
def tryAsHardAsPossibleToFindMatch(s: String) = {
val ls = s.toLowerCase
val fv = values.filter(_.toString.toLowerCase.startsWith(ls))
fv.size match {
case 1 => fv.head
case 0 => sys.error("No matching value for " + s)
case _ => sys.error("Ambiguous values for " + s)
}
}
This will allow you to use any string, regardless of case, that is part of the beginning of a Value. So Vertical can be obtained with "VERT", "vErTi", "vERTICAL", "VerticaL", etc.
I must have some basic misunderstanding of the Scala 'match' semantics or the compiler logic. This code:
val stageStart:Int = 0
val stageShutDown:Int = Int.MaxValue
val stageErrorReport:Int = Int.MinValue
def stageString(stage:Int):String = stage match {
case stageStart => "Start"
case stageShutDown => "End"
case stageErrorReport => "Error"
case _ => "Step " + String.valueOf(stage)
}
results in "Unreachable Code" errors on the last 3 'case' statements? If instead of the names you substitute the actual values (0, Int.MaxValue, Int.MinValue) it compiles -- but now I've hard-coded values that should be referenced by their names (for all the usual reasons). Since a 'val' can never change, shouldn't the first version also work?
There is a subtle yet important feature: If the identifier in case rules start with a lower-case letter, they're always treated as variables. So the first case matches always (storing stage into variable stageStart) and the rest 3 are unreachable. You need to define the constants with upper case letters as
val StageStart:Int = 0
val StageShutDown:Int = Int.MaxValue
val StageErrorReport:Int = Int.MinValue
def stageString(stage:Int):String = stage match {
case StageStart => "Start"
case StageShutDown => "End"
case StageErrorReport => "Error"
case _ => "Step " + String.valueOf(stage)
}
Then they won't be treated as variables but as constants to pattern-match on.
See also this answer for Naming convention for Scala constants?
The issue is that when you use a variable that starts with a lowercase character, the pattern matcher thinks that you are trying to assign to that variable. So you get this behavior:
val stageStart = 0
val stage = 5
def stageString(stage: Int) = stage match {
case stageStart => println(startStage) // prints "5"
}
Of course, a pattern that is simply an assignable variable will match anything, so any subsequent case will be unreachable.
To solve this, you need to use a "stable identifier". This can be done by putting the lowercased variable in backticks:
val stageStart = 0
def stageString(stage: Int) = stage match {
case `stageStart` => "Start"
}
or renaming the variable so that it starts with an uppercase character:
val StageStart = 0
def stageString(stage: Int) = stage match {
case StageStart => "Start"
}
Also: String.valueOf(stage) should be rewritten as stage.toString.
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).
regarding the following scala code, functions m2a and m2b apparently differ only by the case of the parameter, ie abc vs Abc. This seems to make some difference in the result as per example below. When running it with a recent 2.8 compiler, it results in the following (I would have expected all true). Any insights would be appreciated.
m1=true
m2a=true
m2b=false
m3=true
code
package sample
import scala.xml._
object ParamTest extends Application {
def m1(n:Node, abc:String):Boolean = {
n == <id>{Text(abc)}</id>
}
def m2a(n:Node, Abc:String):Boolean = n match {
case <id>{Text(Abc)}</id> => true
case _ => false;
}
// why does this one not work?
def m2b(n:Node, abc:String):Boolean = n match {
case <id>{Text(abc)}</id> => true
case _ => false;
}
def m3(n:Node, abc:String):Boolean = n match {
case Elem(_,"id",_,_, c #_ *) => {
c contains Text(abc)
}
}
def runner(n:Node, f:(Node, String)=>Boolean):Boolean = {
f(n, "x") && !f(n, "y") && !f(n, "");
}
val x = <id>x</id>
println("m1="+runner(x, m1));
println("m2a="+runner(x, m2a));
println("m2b="+runner(x, m2b));
println("m3="+runner(x, m3));
}
The trick here is in how Scala handles variables in case expressions. Lowercase variables in case expressions are taken by the compiler to introduce new variables, which are then pattern matched against. Thus in method m2b, the method parameter "abc" is actually unused. The case expression variable "abc" will match any string, since it is not otherwise constrained. Thus "y" is successfully matched in the first case of m2b. Uppercase variables in case expressions do not introduce new variables, so in m2a the match behaves as you expected.
The easiest way to match against the value of a lowercase variable is to wrap it in backquotes. Thus
def m2b(n:Node, abc:String):Boolean = n match {
case <id>{Text(`abc`)}</id> => true
case _ => false;
}
will give you the results you expected.
In pattern matching, identifiers in the pattern that start with a lower-case letter are taken to be free pattern variables that can be bound to values in the target of the match. Those that start with upper-case letters are so-called stable identifiers and must already be bound in the match expression's context and the value of that binding must equal the subexpression of the match target at the point in that value corresponding to that stable identifier's placement within the pattern expression.
Additionally, and relevant in this particular example, pattern variables (the lower-case names) will shadow any existing binding of the same name that is in effect in the context of the match expression (including the expression supplying the match target value).