This page is no longer maintained — Please continue to the home page at www.scala-lang.org

generalized catch blocks, now available

1 reply
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.

Here's something I always wanted to do, and now I did.

KEY SYNTAX FOR THE IMPATIENT:

try body
catch handler
finally vanish

Where handler is potentially any expression which evaluates to a
PartialFunction[Throwable, T] where T is the type of the body.

Who's up for a little language change? There's no cost to this: all
current catch blocks would compile exactly as they presently do. If the
catch block isn't a sequence of case statements, then the expression
would be transformed into something like

lazy val handler$1 = expr()
try body
catch {
case x if handler$1 isDefinedAt x => handler$1(x)
}
finally vanish

Although at the moment the only thing I've done is let stable ids work,
so there's no arbitrary expression or lazy evaluation.

Here's a very small demo of some things one might do. If it's not
convincing I can gather convincingness. I think this is the missing
piece for being able to write really appealing reusable exception
handling abstractions.

// a.scala
type Handler[+T] = PartialFunction[Throwable, T]
def shortName(x: AnyRef) = x.getClass.getName split '.' last;

val standardHandler: Handler[String] = {
case x: java.util.NoSuchElementException => shortName(x)
case x: java.lang.IllegalArgumentException => shortName(x)
}

def fn[T: Handler](body: => T): T = {
val handler = implicitly[Handler[T]]

try body
catch handler
}

def f1 = {
implicit val myHandler = standardHandler
println(fn(Nil.head))
println(fn(null.toString))
}
def f2 = {
implicit val myHandler: Handler[String] = standardHandler orElse {
case x => "DEBUG: " + shortName(x)
}
println(fn(Nil.head))
println(fn(null.toString))
}

// outputs
scala> f1
NoSuchElementException
java.lang.NullPointerException
at $anonfun$f1$2.apply(:12)
at $anonfun$f1$2.apply(:12)
at .fn(:9)
at .f1(:12)
[snip]

scala> f2
NoSuchElementException
DEBUG: NullPointerException

Viktor Klang
Joined: 2008-12-17,
User offline. Last seen 1 year 27 weeks ago.
Re: generalized catch blocks, now available
Mmmmm shiny

On Thu, Nov 4, 2010 at 6:06 PM, Paul Phillips <paulp [at] improving [dot] org> wrote:
Here's something I always wanted to do, and now I did.

KEY SYNTAX FOR THE IMPATIENT:

 try body
 catch handler
 finally vanish

Where handler is potentially any expression which evaluates to a
PartialFunction[Throwable, T] where T is the type of the body.

Who's up for a little language change? There's no cost to this: all
current catch blocks would compile exactly as they presently do.  If the
catch block isn't a sequence of case statements, then the expression
would be transformed into something like

 lazy val handler$1 = expr()
 try body
 catch {
   case x if handler$1 isDefinedAt x => handler$1(x)
 }
 finally vanish

Although at the moment the only thing I've done is let stable ids work,
so there's no arbitrary expression or lazy evaluation.

Here's a very small demo of some things one might do.  If it's not
convincing I can gather convincingness.  I think this is the missing
piece for being able to write really appealing reusable exception
handling abstractions.

// a.scala
type Handler[+T] = PartialFunction[Throwable, T]
def shortName(x: AnyRef) = x.getClass.getName split '.' last;

val standardHandler: Handler[String] = {
 case x: java.util.NoSuchElementException    => shortName(x)
 case x: java.lang.IllegalArgumentException  => shortName(x)
}

def fn[T: Handler](body: => T): T = {
 val handler = implicitly[Handler[T]]

 try body
 catch handler
}

def f1 = {
 implicit val myHandler = standardHandler
 println(fn(Nil.head))
 println(fn(null.toString))
}
def f2 = {
 implicit val myHandler: Handler[String] = standardHandler orElse {
   case x => "DEBUG: " + shortName(x)
 }
 println(fn(Nil.head))
 println(fn(null.toString))
}

// outputs
scala> f1
NoSuchElementException
java.lang.NullPointerException
       at $anonfun$f1$2.apply(<console>:12)
       at $anonfun$f1$2.apply(<console>:12)
       at .fn(<console>:9)
       at .f1(<console>:12)
       [snip]

scala> f2
NoSuchElementException
DEBUG: NullPointerException

--
Paul Phillips      | Simplicity and elegance are unpopular because
Imperfectionist    | they require hard work and discipline to achieve
Empiricist         | and education to be appreciated.
all hip pupils!    |     -- Dijkstra



--
Viktor Klang,
Code Connoisseur
Work:   Scalable Solutions
Code:   github.com/viktorklang
Follow: twitter.com/viktorklang
Read:   klangism.tumblr.com

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland