Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala catching confusion

I've recently seen code like this:

val maybeInt = catching(classOf[NFE]) opt arg.toInt 

What is this opt? An Option? Why isn't it using getOrElse to extract the value? In the above code, will maybeInt be None if a NumberFormatException gets thrown?

like image 618
Geo Avatar asked Apr 20 '11 18:04

Geo


2 Answers

catching looks like it's some sort of method call, doesn't it? It is, but it actually returns an instance of a class Catch; it doesn't directly take an argument. This class has two methods that are particularly useful for dealing with exceptions (and several more for catching multiple exceptions). The first is

def opt [U >: T] (body: ⇒ U) : Option[U] 

which is being used here--you give it something that may throw an exception, and it will return Some(result) if everything went okay, and None if the targeted exception was caught:

scala> type NFE = NumberFormatException defined type alias NFE  scala> import scala.util.control.Exception._ import scala.util.control.Exception._  scala> catching(classOf[NFE]).opt( "fish".toInt ) res0: Option[Int] = None  scala> catching(classOf[NFE]).opt( "42".toInt )   res1: Option[Int] = Some(42) 

You can then deal with this with map or filter or getOrElse or whatever else you use to deal with options.

The other useful method is either, which returns an instance of Left(exception) if an exception was thrown, and a Right(result) if it was not:

scala> catching(classOf[NFE]).either( "fish".toInt ) res2: Either[Throwable,Int] = Left(java.lang.NumberFormatException: For input string: "fish")  scala> catching(classOf[NFE]).either( "42".toInt ) res3: Either[Throwable,Int] = Right(42) 

You can then use fold or map to an option or whatever else you like doing with eithers.

Note that you can define a single catcher and use it multiple times (so you don't need to create the catcher object every time you, for example, parse an integer):

scala> val catcher = catching(classOf[NFE]) catcher: util.control.Exception.Catch[Nothing] = Catch(java.lang.NumberFormatException)  scala> catcher.opt("42".toInt) res4: Option[Int] = Some(42)  scala> catcher.opt("fish".toInt) res5: Option[Int] = None 

Edit: as Daniel points out in the comments, this still creates a temporary Catch[Option]; given the method signatures, there isn't an easy way to just have it trap exceptions and generate options without creating any extra objects. This reminds me why I write my own methods to do exactly that:

def optNFE[T](t: => T) = try { Some(t) } catch {case nfe: NFE => None} optNFE( "fish".toInt )  // gives None optNFE( "42".toInt ) // gives Some(42) 
like image 72
Rex Kerr Avatar answered Sep 28 '22 04:09

Rex Kerr


I use a more simple pattern when there is only one catch :

 try{       return args.split(" ").exists(line.startsWith _)  }catch {     case _ =>{//generic exception       logger.error("Error with line ${line} for ${ex.message}")       throw _     }      } 

I'm definitely not yet a Scala pro, and I guess you could find shorter stuff

like image 27
Nicolas Zozol Avatar answered Sep 28 '22 05:09

Nicolas Zozol