I'm learning Scala and confused about the try-catch-finally syntax.
In Scala Syntax Specification, it says:
Expr1 ::= ‘try’ Expr [‘catch’ Expr] [‘finally’ Expr]
| ...
Can I write expression without { } blocks like this:
try
println("Hello")
catch
RuntimeException e => println("" + e)
finally
println("World")
Or the expression must be a block expression ?
Scala 3 (Dotty) is experimenting with optional braces (significant indentation) so the following works
scala> try
| 1 / 0
| catch
| case e => println(s"good catch $e")
| finally
| println("Celebration dance :)")
|
good catch java.lang.ArithmeticException: / by zero
Celebration dance :)
val res1: AnyVal = ()
where we note the handler
case e => println(s"good catch $e")
did not need braces as in Scala 2. In fact due to special treatment of case clauses after catch keyword the following would also work
scala> try
| 1 / 0
| catch
| case e => println(s"good catch $e")
| finally
| println("Celebration dance :)")
|
good catch java.lang.ArithmeticException: / by zero
Celebration dance :)
val res2: AnyVal = ()
where we note the handler did not have to be indented after catch
catch
case e => println(s"good catch $e")
Sure.
import scala.util.control.NonFatal
def fourtyseven: PartialFunction[Throwable, Int] = {
case NonFatal(_) => 47
}
def attempt(n: => Int): Int =
try n catch fourtyseven finally println("done")
println(attempt(42))
println(attempt(sys.error("welp")))
This compiles and runs as expected, although I had to define the catch expression separately (as it requires braces).
You can play around with this code here on Scastie.
A few of notes:
try/catch/finally is an expression that returns a value (this could be a bit unfamiliar if you're coming from Java) -- you can read more about it here on the docs
catch always takes a PartialFunction from a Throwable to some type, with the overall return type of the try/catch to be the closest common superclass of the two (e.g. say you have class Animal; class Dog extends Animal; class Cat extends Animal, if the try returns a Dog and the catch returns a Cat the overall expression will return an Animal)
I used the NonFatal extractor in the catch partial function, you can read more about it in this answer, while extractor objects in general are described here in the official docs
Related
I routinely use partial functions to factor out common clauses in exception handling. For example:
val commonHandler: PartialFunction[Throwable, String] = {
case ex: InvalidClassException => "ice"
}
val tried = try {
throw new Exception("boo")
}
catch commonHandler orElse {
case _:Throwable => "water"
}
println(tried) // water
Naturally, I expected that the match keyword also expects a partial function and that I should be able to do something like this:
val commonMatcher: PartialFunction[Option[_], Boolean] = {
case Some(_) => true
case None => false
}
Some(8) match commonMatcher // Compilation error
What am I doing wrong?
The match is a keyword, not a method, and its syntax does not accept a partial function on its right side (see below). There however exists a pipe method (since 2.13), which, same as map or foreach, accepts a partial function. You can therefore write:
import scala.util.chaining._
Some(8).pipe(commonMatcher)
There was some discussion regarding this (see Pre SIP: Demote match keyword to a method) and there was a PR which made possible to use the match a bit more like a method (Change match syntax #7610), with a dot, but still the syntax is the match keyword needs to be followed by case clauses, see https://docs.scala-lang.org/scala3/reference/syntax.html:
InfixExpr ::= ... other variants ommitted here ...
| InfixExpr MatchClause
SimpleExpr ::= ... other variants ommitted here ...
| SimpleExpr ‘.’ MatchClause
MatchClause ::= ‘match’ <<< CaseClauses >>>
CaseClauses ::= CaseClause { CaseClause }
CaseClause ::= ‘case’ Pattern [Guard] ‘=>’ Block
Compare this with catch syntax:
Expr1 ::= ... other variants ommitted here ...
| ‘try’ Expr Catches [‘finally’ Expr]
Catches ::= ‘catch’ (Expr | ExprCaseClause)
I am writing a parser for boolean expressions, and try to parse input like "true and false"
def boolExpression: Parser[BoolExpression] = boolLiteral | andExpression
def andExpression: Parser[AndExpression] = (boolExpression ~ "and" ~ boolExpression) ^^ {
case b1 ~ "and" ~ b2 => AndExpression(b1, b2)
}
def boolLiteral: Parser[BoolLiteral] = ("true" | "false") ^^ {
s => BoolLiteral(java.lang.Boolean.valueOf(s))
}
The above code does not parse "true and false", since it reads only "true" and applies rule boolLiteral immediately
But if I change the rule boolExpression to this:
def boolExpression: Parser[BoolExpression] = andExpression | boolLiteral
Then, when parsing "true and false", the code throws a StackoverflowError due to endless recursion
java.lang.StackOverflowError
at Parser.boolExpression(NewParser.scala:58)
at Parser.andExpression(NewParser.scala:62)
at Parser.boolExpression(NewParser.scala:58)
at Parser.andExpression(NewParser.scala:62)
...
How to solve this?
This appears to be parsing a string of boolean constants separated by "and" which is best done using the chainl1 primitive in the parser. This process a chain of operations a op b op c op d using left-to-right precedence.
It might look something like this totally untested code:
trait BoolExpression
case class BoolLiteral(value: Boolean) extends BoolExpression
case class AndExpression(l: BoolExpression, r: BoolExpression) extends BoolExpression
def boolLiteral: Parser[BoolLiteral] =
("true" | "false") ^^ { s => BoolLiteral(java.lang.Boolean.valueOf(s)) }
def andExpression: Parser[(BoolExpression, BoolExpression) => BoolExpression] =
"and" ^^ { _ => (l: BoolExpression, r: BoolExpression) => AndExpression(l, r) }
def boolExpression: Parser[BoolExpression] =
chainl1(boolLiteral, andExpression) ^^ { expr => expr }
Presumably the requirement is more complex than this, but the chainl1 parser is a good starting point.
The core of the issue is that the usual parser combinator libraries use parsing algorithms that don't support left recursion. One solution is to rewrite the grammar without left recursion, meaning that every parser needs to consume at least some input before invoking itself recursively. For instance, your grammar can be written like so:
def boolExpression: Parser[BoolExpression] = andExpression | boolLiteral
def andExpression: Parser[AndExpression] = (boolLiteral ~ "and" ~ boolExpression) ^^ {
case b1 ~ "and" ~ b2 => AndExpression(b1, b2)
}
But you can also use a parser combinator library that's based on another parsing algorithm that supports left recursion. I'm only aware of one for Scala:
https://github.com/djspiewak/gll-combinators
I don't know to what degree it is production ready.
//edit:
I think this one might also support left recursion. Again, I don't know the degree to which it is production ready.
https://github.com/djspiewak/parseback
Is there a way in Scala to explicity tell a function that you want to use the default arguments?
Example
def myFunction(default : Int = 0) { /* logic */ }
myFunction(number match {
case 5 => 5
case _ => ???
})
Is it possible to replace ??? with something that will act as calling the function with the default? (Of course, I could replace with 0, but assume this example for simplicity)
Thanks
number match {
case 5 => myFunction(5)
case _ => myFunction()
}
I think You can do it by using pattern match with function call.
The right way is what #chengpohi suggests. The only way to do exactly what you asked is to mess with how scalac implements default arguments under the hood:
myFunction(number match {
case 5 => 5
case _ => myFunction$default$1
})
But that is very much not recommended.
Also mind that this will probably not work when pasted without adaptation in the REPL, because the REPL wraps things in additional objects and you'll have to know the absolute path to myFunction$default$1. To test it in the REPL you'll have to wrap it in an object or class:
scala> object Foo {
| def myFunction(a: Int = 0) = println(a)
|
| val number = 42
| myFunction(number match {
| case 5 => 5
| case _ => myFunction$default$1
| })
| }
defined object Foo
scala> Foo
0
res5: Foo.type = Foo$#2035f1f0
assume two parsers: p & q.
now, given the following code:
val p1 = p | q
val p2 = "$" ~> p1 <~ "$"
something weird is happening. assume some string: val input = "..."
parseAll(p1, input)
succeeds with p's parsing result, but:
parseAll(p2, "$" + input +"$")
succeeds with q's parsing result.
the order is important. I only want to try q after p failed.
is there any way I can force the parser to evaluate p before q?
EDIT:
after checking the docs more carefully:
p | q succeeds if p succeeds or q succeeds.
Note that q is only tried if ps failure is non-fatal (i.e., back-tracking is allowed).
so my code should work.
so I tried reproducing with a simple example (my original code is too use case specific and most of it not relevant for here). but didn't quite succeed. instead, I managed to come up with a parser that fails when it should succeed. shown in the following REPL session:
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.util.parsing.combinator._
import scala.util.parsing.combinator._
scala> object MyParser extends RegexParsers {
| val xyz = "xyz".r ^^ { case s => Right(s) }
| val any = "\\S+".r ^^ { case s => Left(s) }
| val either: Parser[Either[String,String]] = xyz | any
| val wrapped = "$" ~> either <~ "$"
| def parseMeATest1(input: String) = parseAll(either, input) match {
| case Success(Right(s),_) => println(s"right: $s")
| case Success(Left(s),_) => println(s"left: $s")
| case NoSuccess(msg, _) => println(msg)
| }
| def parseMeATest2(input: String) = parseAll(wrapped, input) match {
| case Success(Right(s),_) => println(s"right: $s")
| case Success(Left(s),_) => println(s"left: $s")
| case NoSuccess(msg, _) => println(msg)
| }
| }
defined object MyParser
scala> MyParser.parseMeATest1("xyz")
right: xyz
scala> MyParser.parseMeATest1("zzz")
left: zzz
scala> MyParser.parseMeATest2("$xyz$")
right: xyz
scala> MyParser.parseMeATest2("$zzz$")
`$' expected but end of source found
So, am I missing something here, or this a bug with scala parsing combinators?
SOLVED:
problem was that p parser consumed the trailing $ character, causing overall failure, but since backtracking is used, q which does not consume the $ character completed successfully.
Option monad is a great expressive way to deal with something-or-nothing things in Scala. But what if one needs to log a message when "nothing" occurs? According to the Scala API documentation,
The Either type is often used as an
alternative to scala.Option where Left
represents failure (by convention) and
Right is akin to Some.
However, I had no luck to find best practices using Either or good real-world examples involving Either for processing failures. Finally I've come up with the following code for my own project:
def logs: Array[String] = {
def props: Option[Map[String, Any]] = configAdmin.map{ ca =>
val config = ca.getConfiguration(PID, null)
config.properties getOrElse immutable.Map.empty
}
def checkType(any: Any): Option[Array[String]] = any match {
case a: Array[String] => Some(a)
case _ => None
}
def lookup: Either[(Symbol, String), Array[String]] =
for {val properties <- props.toRight('warning -> "ConfigurationAdmin service not bound").right
val logsParam <- properties.get("logs").toRight('debug -> "'logs' not defined in the configuration").right
val array <- checkType(logsParam).toRight('warning -> "unknown type of 'logs' confguration parameter").right}
yield array
lookup.fold(failure => { failure match {
case ('warning, msg) => log(LogService.WARNING, msg)
case ('debug, msg) => log(LogService.DEBUG, msg)
case _ =>
}; new Array[String](0) }, success => success)
}
(Please note this is a snippet from a real project, so it will not compile on its own)
I'd be grateful to know how you are using Either in your code and/or better ideas on refactoring the above code.
Either is used to return one of possible two meaningful results, unlike Option which is used to return a single meaningful result or nothing.
An easy to understand example is given below (circulated on the Scala mailing list a while back):
def throwableToLeft[T](block: => T): Either[java.lang.Throwable, T] =
try {
Right(block)
} catch {
case ex => Left(ex)
}
As the function name implies, if the execution of "block" is successful, it will return "Right(<result>)". Otherwise, if a Throwable is thrown, it will return "Left(<throwable>)". Use pattern matching to process the result:
var s = "hello"
throwableToLeft { s.toUpperCase } match {
case Right(s) => println(s)
case Left(e) => e.printStackTrace
}
// prints "HELLO"
s = null
throwableToLeft { s.toUpperCase } match {
case Right(s) => println(s)
case Left(e) => e.printStackTrace
}
// prints NullPointerException stack trace
Hope that helps.
Scalaz library has something alike Either named Validation. It is more idiomatic than Either for use as "get either a valid result or a failure".
Validation also allows to accumulate errors.
Edit: "alike" Either is complettly false, because Validation is an applicative functor, and scalaz Either, named \/ (pronounced "disjonction" or "either"), is a monad.
The fact that Validation can accumalate errors is because of that nature. On the other hand, / has a "stop early" nature, stopping at the first -\/ (read it "left", or "error") it encounters. There is a perfect explanation here: http://typelevel.org/blog/2014/02/21/error-handling.html
See: http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html
As requested by the comment, copy/paste of the above link (some lines removed):
// Extracting success or failure values
val s: Validation[String, Int] = 1.success
val f: Validation[String, Int] = "error".fail
// It is recommended to use fold rather than pattern matching:
val result: String = s.fold(e => "got error: " + e, s => "got success: " + s.toString)
s match {
case Success(a) => "success"
case Failure(e) => "fail"
}
// Validation is a Monad, and can be used in for comprehensions.
val k1 = for {
i <- s
j <- s
} yield i + j
k1.toOption assert_≟ Some(2)
// The first failing sub-computation fails the entire computation.
val k2 = for {
i <- f
j <- f
} yield i + j
k2.fail.toOption assert_≟ Some("error")
// Validation is also an Applicative Functor, if the type of the error side of the validation is a Semigroup.
// A number of computations are tried. If the all success, a function can combine them into a Success. If any
// of them fails, the individual errors are accumulated.
// Use the NonEmptyList semigroup to accumulate errors using the Validation Applicative Functor.
val k4 = (fNel <**> fNel){ _ + _ }
k4.fail.toOption assert_≟ some(nel1("error", "error"))
The snippet you posted seems very contrived. You use Either in a situation where:
It's not enough to just know the data isn't available.
You need to return one of two distinct types.
Turning an exception into a Left is, indeed, a common use case. Over try/catch, it has the advantage of keeping the code together, which makes sense if the exception is an expected result. The most common way of handling Either is pattern matching:
result match {
case Right(res) => ...
case Left(res) => ...
}
Another interesting way of handling Either is when it appears in a collection. When doing a map over a collection, throwing an exception might not be viable, and you may want to return some information other than "not possible". Using an Either enables you to do that without overburdening the algorithm:
val list = (
library
\\ "books"
map (book =>
if (book \ "author" isEmpty)
Left(book)
else
Right((book \ "author" toList) map (_ text))
)
)
Here we get a list of all authors in the library, plus a list of books without an author. So we can then further process it accordingly:
val authorCount = (
(Map[String,Int]() /: (list filter (_ isRight) map (_.right.get)))
((map, author) => map + (author -> (map.getOrElse(author, 0) + 1)))
toList
)
val problemBooks = list flatMap (_.left.toSeq) // thanks to Azarov for this variation
So, basic Either usage goes like that. It's not a particularly useful class, but if it were you'd have seen it before. On the other hand, it's not useless either.
Cats has a nice way to create an Either from exception-throwing code:
val either: Either[NumberFormatException, Int] =
Either.catchOnly[NumberFormatException]("abc".toInt)
// either: Either[NumberFormatException,Int] = Left(java.lang.NumberFormatException: For input string: "abc")
in https://typelevel.org/cats/datatypes/either.html#working-with-exception-y-code