try-catch-finally を scala.util.control.Exception で書いてみる

11 月 10 日に daimon.scala Scala School#1 に参加してきました。

Scala School (http://twitter.github.com/scala_school/basics2.html) の Exceptions のところ、try-catch-finally を使う例に対して「優れたプログラミングスタイルの例ではありません。」(@seratch による日本語訳はこちら http://d.hatena.ne.jp/seratch2/20111101/1320162713) とあるけどじゃあ優れたスタイルってなんだよという話がありました。もしかしたら scala.util.control.Exception で書くのが良いかもという意見があり、僕もそう思ったので実装してみました。

Scala School の例

val result: Int = try {
  remoteCalculatorService.add(1, 2)
} catch {
  case e: ServerIsDownException => {
    log.error(e, "the remote calculator service is unavailble. should have kept your trustry HP.")
    0
  }
} finally {
  remoteCalculatorService.close()
}

scala.util.control.Exception を使って書いてみた

import scala.util.control.Exception._

class ServerIsDownException extends Exception

object A extends App {
  val remoteCalculatorService = new AnyRef {
    def add(a: Int, b: Int): Int = {
      a + b match {
        case odd if odd % 2 == 1 => odd
        case _ => throw new ServerIsDownException
      }  
    }
    def close {}
  }
  val log = new AnyRef { def error(t: Throwable, m: String) { println(m) } }

  def add(a: Int, b: Int): Int = {
    catching(classOf[ServerIsDownException]).
      andFinally { remoteCalculatorService.close }. 
      either { remoteCalculatorService.add(a, b) } match {
        case Right(x) => x
        case Left(t)=> {
          log.error(t, "the remote calculator service is unavailble. should have kept your trustry HP.")
          0
        }
      }
  }
    
  println("1 + 2 =" + add(1, 2))
  println("1 + 1 =" + add(1, 1))
} 

んー、わかりにくいかな?
scala.util.control.Exception は

ignoring(classOf[SQLException]) opt conn.close

とかやるときは try-finally より簡潔に書けるけど、catch 節の表現はわかりにくくなるかも?