How can I avoid always putting
case _ =>
at the end in Scala matching? It is sometimes possible that other values will be matched, but I only want to do something with the cases above the
"case _ =>"
case.
A match is a function like most things in Scala, so it returns a value and you need to return something for every possible case. If you are not doing anything in case _ then you are returning Unit which, in turn, means that the code is relying on side effects and is non-functional.
So the best way to reduce the use of empty case _ => in your code is to make it more functional, since this isn't used in functional code.
The alternative is to use a different mechanism for a multi-way branch, such as chained if, or chains of Option/orElse, or find/collectFirst on a list of operations.
Related
I'm currently working on my functional programming - I am fairly new to it. Am i using Options correctly here? I feel pretty insecure on my skills currently. I want my code to be as safe as possible - Can any one point out what am I doing wrong here or is it not that bad? My code is pretty straight forward here:
def main(args: Array[String]): Unit =
{
val file = "myFile.txt"
val myGame = Game(file) //I have my game that returns an Option here
if(myGame.isDefined) //Check if I indeed past a .txt file
{
val solutions = myGame.get.getAllSolutions() //This returns options as well
if(solutions.isDefined) //Is it possible to solve the puzzle(crossword)
{
for(i <- solutions.get){ //print all solutions to the crossword
i.solvedCrossword foreach println
}
}
}
}
-Thanks!! ^^
When using Option, it is recommended to use match case instead of calling 'isDefined' and 'get'
Instead of the java style for loop, use higher-order function:
myGame match {
case Some(allSolutions) =>
val solutions = allSolutions.getAllSolutions
solutions.foreach(_.solvedCrossword.foreach(println))
case None =>
}
As a rule of thumb, you can think of Option as a replacement for Java's null pointer. That is, in cases where you might want to use null in Java, it often makes sense to use Option in Scala.
Your Game() function uses None to represent errors. So you're not really using it as a replacement for null (at least I'd consider it poor practice for an equivalent Java method to return null there instead of throwing an exception), but as a replacement for exceptions. That's not a good use of Option because it loses error information: you can no longer differentiate between the file not existing, the file being in the wrong format or other types of errors.
Instead you should use Either. Either consists of the cases Left and Right where Right is like Option's Some, but Left differs from None in that it also takes an argument. Here that argument can be used to store information about the error. So you can create a case class containing the possible types of errors and use that as an argument to Left. Or, if you never need to handle the errors differently, but just present them to the user, you can use a string with the error message as the argument to Left instead of case classes.
In getAllSolutions you're just using None as a replacement for the empty list. That's unnecessary because the empty list needs no replacement. It's perfectly fine to just return an empty list when there are no solutions.
When it comes to interacting with the Options, you're using isDefined + get, which is a bit of an anti pattern. get can be used as a shortcut if you know that the option you have is never None, but should generally be avoided. isDefined should generally only be used in situations where you need to know whether an option contains a value, but don't need to know the value.
In cases where you need to know both whether there is a value and what that value is, you should either use pattern matching or one of Option's higher-order functions, such as map, flatMap, getOrElse (which is kind of a higher-order function if you squint a bit and consider by-name arguments as kind-of like functions). For cases where you want to do something with the value if there is one and do nothing otherwise, you can use foreach (or equivalently a for loop), but note that you really shouldn't do nothing in the error case here. You should tell the user about the error instead.
If all you need here is to print it in case all is good, you can use for-comprehension which is considered quite idiomatic Scala way
for {
myGame <- Game("mFile.txt")
solutions <- myGame.getAllSolutions()
solution <- solutions
crossword <- solution.solvedCrossword
} println(crossword)
Here is a description about cata function from scalaz. But what is a purpose og using this function? By the way is there a scaladoc for scalaz with description, not only code.
It's the same as fold on scala.Option: it lets you map both the has-a-value branch and the empty branch into a single result value. Anywhere you might see
Option(x) match {
case Some(y) => f(y)
case None => y0
}
you can use fold on Option or cata on scalaz' variant instead.
(Note: for this particular case, pattern matching is typically more efficient, but not always more convenient.)
Suppose I have some type with an associative binary operation that feels a lot like append except that the operation may fail. For example, here's a wrapper for List[Int] that only allows us to "add" lists with the same length:
case class Foo(xs: List[Int]) {
def append(other: Foo): Option[Foo] =
if (xs.size != other.xs.size) None else Some(
Foo(xs.zip(other.xs).map { case (a, b) => a + b })
)
}
This is a toy example, but one of the things it has in common with my real use case is that we could in principle use the type system to make the operation total—in this case by tracking the length of the lists with something like Shapeless's Sized, so that adding lists of unequal lengths would be a compile-time error instead of a runtime failure. That's not too bad, but in my real use case managing the constraints in the type system would require a lot more work and isn't really practical.
(In my use case I have a sensible identity, unlike in this toy example, but we can ignore that for now.)
Is there some principled way to do this kind of thing? Searching for a -> a -> m a or a -> a -> Maybe a on Hoogle doesn't turn up anything interesting. I know I can write an ad-hoc append method that just returns its result wrapped in whatever type I'm using to model failure, but it'd be nice to have something more general that would give me foldMap1, etc. for free—especially since this isn't the first time I've found myself wanting this kind of thing.
I often find myself wanting to clump multiple matchers / extractors into the one line, but this doesn't seem to be allowed. e.g.:
text match {
case regex1(a) | regex2(a) => a + "-"
}
(even though a is the same type for both matchers)
so I'm forced to refactor like this (which can get ugly when there are several of these, all handling different matches, mixed with inline responses)
text match {
case regex1(a) => op(a)
case regex2(a) => op(a)
}
def op(a: String) = a + "-"
is there a cleaner way? And will this be supported in Scala in the future?
No, this is not possible in the general case. However, there are a few workaround that might be use to combine pattern matching cases:
Match on a super class of the cases you are willing to group
Use the case a # _ if boolexpr(a) or boolexpr(a) => construction
Factorize the common code in a function, like you did in your example
And probably others. I don't think this is going to change any time soon as it would encourage writing cryptic mach/cases.
Given a variable with type Graphics,
how do I cast it to Graphics2D in Scala?
The preferred technique is to use pattern matching. This allows you to gracefully handle the case that the value in question is not of the given type:
g match {
case g2: Graphics2D => g2
case _ => throw new ClassCastException
}
This block replicates the semantics of the asInstanceOf[Graphics2D] method, but with greater flexibility. For example, you could provide different branches for various types, effectively performing multiple conditional casts at the same time. Finally, you don't really need to throw an exception in the catch-all area, you could also return null (or preferably, None), or you could enter some fallback branch which works without Graphics2D.
In short, this is really the way to go. It's a little more syntactically bulky than asInstanceOf, but the added flexibility is almost always worth it.
g.asInstanceOf[Graphics2D];