I find myself repeating simple try/catch blocks that should, IMO, be 1-liners.
For example, let's say I need to convert a uri string date in yyyymmdd format to Joda-Time. With a standard try/catch block the conversion method looks like:
def ymd2Date(ymd: Option[String]) = ymd match {
case Some(date) =>
try { Right( ymdFormat.parseDateTime(date) ) }
catch { case e =>
log.info(e.getMessage)
Left(None)
}
case None =>
Left(None) // no uri date param
}
val ymdFormat = DateTimeFormat.forPattern("yyyyMMdd")
Works well enough, intent is clear, but when I do this kind of try/catch logging for all non-critical events, then I seek a way to DRY it out. The search led me to this SO post on scala.util.control.Exception. Helpful, but it's still a bit difficult to grok/make it work in the way I'd like it to. In plain English I just want to say, "catch some-action get-result log-error-type".
So, I hacked this out based on the part of control.Exception I'm interested in (or understand to be useful):
class Catcher[T](f: => T) {
type Logger = (=> Any) => Unit
def either[T]( logger: => Logger ) = {
try { Right(f) }
catch { case e =>
logger(e.getMessage)
Left(None)
}
}
}
def catching[T](f: => T) = new Catcher(f)
And then use in place of try/catch like so:
catching( ymdFormat.parseDateTime(date) ) either log.info
Can add on option, a msg prefix, etc., but...it would probably be better to find a way to get control.Exception to work like the above, as the TypeSafe crew is going to produce code worlds better than I'll ever imagine writing.
Does anyone know how to create this kind of syntax using control.Exception where one can pass in a logger function by-name to be used in the catch block?
Would be great if there was a "use cases" for control.Exception, but I get the feeling this utility is for more advanced Scala devs
This should do what you want:
import scala.util.control.Exception
def log(logger: => Logger)(e: Throwable) = {
logger(e.getMessage)
None
}
Exception.allCatch withApply log(logger) apply Some(ymdFormat.parseDateTime(date))
But this kind of stuff is better handled by Scalaz Validation
, in my opinion.
A quick example:
import scala.util.control.Exception._
def throwingStuff {
throw new Exception("Hello World!")
}
catching(classOf[Exception]).withApply{err => println(err.toString); None}.apply(Some(throwingStuff))
You can use withApply
to override the application logic of the Catch
class to do something such as writing to a log.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With