3
\$\begingroup\$
override def get(key: String): Option[Any] = {
 val timer = couchbaseMetricsTimer.time()
 try { // Any way (is it more elegant?) to avoid the try/catch/finally?
 Option(couchBaseClient.get(key))
 } catch {
 case e: Exception => couchbaseFailureMetricCounter.inc(); throw e
 } finally {
 timer.stop()
 }
}

Note the clients of this code are expecting exceptions in case of failures.

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Aug 26, 2014 at 8:44
\$\endgroup\$
3
  • \$\begingroup\$ If you are just going to re-throw the exception, why bother catching it at all? Just try-finally should suffice. \$\endgroup\$ Commented Aug 26, 2014 at 15:24
  • \$\begingroup\$ because i'm calling a failure metric couchbaseFailureMetricCounter.inc() to increment failure counter whenever i get an exception. \$\endgroup\$ Commented Aug 27, 2014 at 3:50
  • 1
    \$\begingroup\$ scala-lang.org/api/current/… You may want take a look at this \$\endgroup\$ Commented Sep 2, 2014 at 8:12

2 Answers 2

3
\$\begingroup\$

You could use Try utility.

But the main concern is that it doesn't support finally statement out-of-the-box.

This can be achieved with some Try enhancement's value class (by Viktor Klang):

implicit class TryOps[T](val t: Try[T]) extends AnyVal {
 def eventually[Ignore](effect: => Ignore): Try[T] = {
 val ignoring = (_: Any) => { effect; t }
 t transform (ignoring, ignoring)
 }
}

Consider this code:

val timer = couchbaseMetricsTimer.time()
val tryClient =
 Try(couchBaseClient.get(key)) map { //convert success result
 Option(_)
 } recover { //process failure result
 case e: Exception => couchbaseFailureMetricCounter.inc(); throw e
 } eventually { //perform "finally" block
 timer.stop()
 }
//return actual result
tryClient.get

It's not less, by more idiomatic, so it's up to you which way to choose.

Here are more references to discover.

Note: you can put TryOps into package object of some of your root package f.e. com.mycompany, and then you can use it everywhere in your project.

answered Aug 29, 2014 at 16:34
\$\endgroup\$
2
  • 2
    \$\begingroup\$ It's nice that Scala allows to create objects capable of doing what language constructs usually do, but is there any advantage of doing it in this case? The original code is perfectly clear to me (as a Java programmer), the rewritten is sort of clear too, but only because it looks about the same. \$\endgroup\$ Commented Aug 29, 2014 at 18:30
  • 2
    \$\begingroup\$ In this particular case there seem no difference. But in general, Try is monadic construction, which allows you to work with it correspondingly, e.g. avoid unnecessary checks and use chaining calls (f.e. several maps in a row). Also Try can be perfectly useful, when you don't need to have exception thrown immediately in the same thread. By the link I provided in answer more information about features of Try. \$\endgroup\$ Commented Aug 29, 2014 at 18:45
1
\$\begingroup\$

An interesting approach to this might be to treat the timer as a resource using the scala-arm library.

You could provide your own implicit implementation of the Resource type class for the timer so that it would automatically be stopped when it exits the managed scope or if an exception occurs. Ideally you could also increment your analytics counter in the resource implementation. This would completely eliminate the need for the try/catch/finally. This would only work, however, if the couchbaseFailureMetricCounter can somehow be referenced there. I would have to see the code or scaladocs for the metrics classes to understand whether that would make sense or not.

The concept would go something like this:

import resource._
override def get(key: String): Option[Any] =
 managed(couchbaseMetricsTimer.time()) acquireAndGet { _ ⇒
 Option(couchBaseClient.get(key))
 }

And then, somewhere in the implicit scope, provide the Resource implementation for the timer type, here assumed to be Timer. The preferred place to put it would be in the companion object of the Timer class (if you own the code for that class):

import scala.resource.Resource
object Timer {
 implicit object TimerResource extends Resource[Timer] {
 def close(timer) = timer.stop()
 def closeAfterException(timer, throwable) = {
 // not sure where this counter would come from, perhaps
 // it could be mixed in or imported
 couchbaseFailureMetricCounter.inc()
 // super implementation also calls close
 super.closeAfterException(timer, throwable)
 }
 }
}
answered Oct 26, 2014 at 19:39
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.