summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-04-11 22:24:21 +0000
committerPaul Phillips <paulp@improving.org>2010-04-11 22:24:21 +0000
commitbf3e7d490048f3b5d07a739e1283ac47173036a5 (patch)
treecb78f3dccdda2a3ff2f7818a1b25b191eb0c54a9 /src/library
parentebe772d693c6957c041d1be58dfd6f7686c2645b (diff)
downloadscala-bf3e7d490048f3b5d07a739e1283ac47173036a5.tar.gz
scala-bf3e7d490048f3b5d07a739e1283ac47173036a5.tar.bz2
scala-bf3e7d490048f3b5d07a739e1283ac47173036a5.zip
Reverting r21442 the Exception patch because I ...
Reverting r21442 the Exception patch because I think it is the cause of the deadlocking. Not my greatest weekend. No review.
Diffstat (limited to 'src/library')
-rw-r--r--src/library/scala/util/control/Exception.scala142
1 files changed, 64 insertions, 78 deletions
diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala
index 3ad5b30f7b..356b11df51 100644
--- a/src/library/scala/util/control/Exception.scala
+++ b/src/library/scala/util/control/Exception.scala
@@ -1,12 +1,9 @@
package scala.util.control
import collection.immutable.List
-import java.lang.reflect.InvocationTargetException
/** Classes representing the components of exception handling.
- * Each class is independently composable. Some example usages:
- *
- *
+ * Each class is independently composable. Some common uses:
*
* <pre>
* <b>import</b> scala.util.control.Exception._
@@ -16,33 +13,33 @@ import java.lang.reflect.InvocationTargetException
* <b>val</b> x1 = catching(classOf[MalformedURLException]) opt new URL(s)
* <b>val</b> x2 = catching(classOf[MalformedURLException], classOf[NullPointerException]) either new URL(s)
* </pre>
- *
* @author Paul Phillips
*/
-object Exception {
- type Catcher[+T] = PartialFunction[Throwable, T]
+import java.lang.reflect.InvocationTargetException
- def mkCatcher[Ex <: Throwable, T](isDef: Ex => Boolean, f: Ex => T) = new Catcher[T] {
- private def downcast(x: Throwable): Option[Ex] =
- if (x.isInstanceOf[Ex]) Some(x.asInstanceOf[Ex]) else None
+object Exception
+{
+ // We get lots of crashes using this, so for now we just use Class[_]
+ // type ExClass = Class[_ <: Throwable]
- def isDefinedAt(x: Throwable) = downcast(x) exists isDef
- def apply(x: Throwable): T = f(downcast(x).get)
- }
- def mkThrowableCatcher[T](isDef: Throwable => Boolean, f: Throwable => T) = mkCatcher(isDef, f)
-
- implicit def throwableSubtypeToCatcher[Ex <: Throwable, T](pf: PartialFunction[Ex, T]) =
- mkCatcher(pf.isDefinedAt _, pf.apply _)
-
- /** !!! Not at all sure of every factor which goes into this,
- * and/or whether we need multiple standard variations.
- */
- def shouldRethrow(x: Throwable): Boolean = x match {
- case _: ControlThrowable => true
- case _: InterruptedException => true
- // case _: java.lang.Error => true ?
- case _ => false
+ type Catcher[+T] = PartialFunction[Throwable, T]
+ type ExceptionCatcher[+T] = PartialFunction[Exception, T]
+
+ // due to the magic of contravariance, Throwable => T is a subtype of
+ // Exception => T, not the other way around. So we manually construct
+ // a Throwable => T and simply rethrow the non-Exceptions.
+ implicit def fromExceptionCatcher[T](pf: ExceptionCatcher[T]): Catcher[T] = {
+ new PartialFunction[Throwable, T] {
+ def isDefinedAt(x: Throwable) = x match {
+ case e: Exception if pf.isDefinedAt(e) => true
+ case _ => false
+ }
+ def apply(x: Throwable) = x match {
+ case e: Exception if pf.isDefinedAt(e) => pf(e)
+ case e => throw e
+ }
+ }
}
trait Described {
@@ -64,37 +61,30 @@ object Exception {
def invoke(): Unit = { body }
}
- /** A container class for catch/finally logic.
- *
- * Pass a different value for rethrow if you want to probably
- * unwisely allow catching control exceptions and other throwables
- * which the rest of the world may expect to get through.
- */
- class Catch[+T](
- val pf: Catcher[T],
- val fin: Option[Finally] = None,
- val rethrow: Throwable => Boolean = shouldRethrow)
- extends Described {
-
+ /** A container class for catch/finally logic. */
+ class Catch[+T] private[Exception](
+ private[Exception] val pf: Catcher[T],
+ private[Exception] val fin: Option[Finally])
+ extends Described
+ {
+ def this(pf: Catcher[T]) = this(pf, None)
protected val name = "Catch"
/** Create a new Catch with additional exception handling logic. */
- def or[U >: T](pf2: Catcher[U]): Catch[U] = new Catch(pf orElse pf2, fin, rethrow)
+ def or[U >: T](pf2: Catcher[U]): Catch[U] = new Catch(pf orElse pf2, fin)
def or[U >: T](other: Catch[U]): Catch[U] = or(other.pf)
/** Apply this catch logic to the supplied body. */
- def apply[U >: T](body: => U): U =
- try body
- catch {
- case x if rethrow(x) => throw x
- case x if pf isDefinedAt x => pf(x)
- }
- finally fin map (_.invoke())
+ def apply[U >: T](body: => U): U = {
+ try { body }
+ catch { case e if pf.isDefinedAt(e) => pf(e) }
+ finally { fin.map(_.invoke()) }
+ }
/* Create an empty Try container with this Catch and the supplied Finally */
def andFinally(body: => Unit): Catch[T] = fin match {
- case None => new Catch(pf, Some(new Finally(body)), rethrow)
- case Some(f) => new Catch(pf, Some(f and body), rethrow)
+ case None => new Catch(pf, Some(new Finally(body)))
+ case Some(f) => new Catch(pf, Some(f and body))
}
/** Apply this catch logic to the supplied body, mapping the result
@@ -110,12 +100,12 @@ object Exception {
/** Create a new Catch with the same isDefinedAt logic as this one,
* but with the supplied apply method replacing the current one. */
- def withApply[U](f: Throwable => U): Catch[U] = {
- val pf2 = new Catcher[U] {
+ def withApply[U](f: (Throwable) => U): Catch[U] = {
+ val pf2 = new PartialFunction[Throwable, U] {
def isDefinedAt(x: Throwable) = pf isDefinedAt x
def apply(x: Throwable) = f(x)
}
- new Catch(pf2, fin, rethrow)
+ new Catch(pf2, fin)
}
/** Convenience methods. */
@@ -149,37 +139,27 @@ object Exception {
override def toString() = List("Try(<body>)", catcher.toString) mkString " "
}
- final val nothingCatcher: Catcher[Nothing] = mkThrowableCatcher(_ => false, throw _)
- final def allCatcher[T]: Catcher[T] = mkThrowableCatcher(_ => true, throw _)
+ final val nothingCatcher: PartialFunction[Throwable, Nothing] =
+ new PartialFunction[Throwable, Nothing] {
+ def isDefinedAt(x: Throwable) = false
+ def apply(x: Throwable) = throw x
+ }
+
+ /** A Catch object which catches everything. */
+ final def allCatch[T]: Catch[T] = new Catch[T]({ case x => throw x }) withDesc "<everything>"
/** The empty Catch object. */
final val noCatch: Catch[Nothing] = new Catch(nothingCatcher) withDesc "<nothing>"
- /** A Catch object which catches everything. */
- final def allCatch[T]: Catch[T] = new Catch(allCatcher[T]) withDesc "<everything>"
-
/** Creates a Catch object which will catch any of the supplied exceptions.
- * Since the returned Catch object has no specific logic defined and will simply
- * rethrow the exceptions it catches, you will typically want to call "opt" or
- * "either" on the return value, or assign custom logic by calling "withApply".
- *
- * Note that Catch objects automatically rethrow ControlExceptions and others
- * which should only be caught in exceptional circumstances. If you really want
- * to catch exactly what you specify, use "catchingPromiscuously" instead.
- */
+ * Since the returned Catch object has no specific logic defined and will simply
+ * rethrow the exceptions it catches, you will typically want to call "opt" or
+ * "either" on the return value, or assign custom logic by calling "withApply".
+ */
def catching[T](exceptions: Class[_]*): Catch[T] =
- new Catch(pfFromExceptions(exceptions : _*)) withDesc (exceptions map (_.getName) mkString ", ")
-
+ new Catch(pfFromExceptions(exceptions : _*)) withDesc exceptions.map(_.getName).mkString(", ")
def catching[T](c: Catcher[T]): Catch[T] = new Catch(c)
- /** Creates a Catch object which will catch any of the supplied exceptions.
- * Unlike "catching" which filters out those in shouldRethrow, this one will
- * catch whatever you ask of it: ControlThrowable, InterruptedException,
- * OutOfMemoryError, you name it.
- */
- def catchingPromiscuously[T](exceptions: Class[_]*): Catch[T] = catchingPromiscuously(pfFromExceptions(exceptions : _*))
- def catchingPromiscuously[T](c: Catcher[T]): Catch[T] = new Catch(c, None, _ => false)
-
/** Creates a Catch object which catches and ignores any of the supplied exceptions. */
def ignoring(exceptions: Class[_]*): Catch[Unit] =
catching(exceptions: _*) withApply (_ => ())
@@ -188,10 +168,6 @@ object Exception {
def failing[T](exceptions: Class[_]*): Catch[Option[T]] =
catching(exceptions: _*) withApply (_ => None)
- /** Creates a Catch object which maps all the supplied exceptions to the given value. */
- def failAsValue[T](exceptions: Class[_]*)(value: => T): Catch[T] =
- catching(exceptions: _*) withApply (_ => value)
-
/** Returns a partially constructed Catch object, which you must give
* an exception handler function as an argument to "by". Example:
* handling(ex1, ex2) by (_.printStackTrace)
@@ -207,6 +183,16 @@ object Exception {
/** Returns a Catch object with no catch logic and the argument as Finally. */
def ultimately[T](body: => Unit): Catch[T] = noCatch andFinally body
+ /** Experimental */
+ def saving[A](oldVal: A, newVal: A, setter: (A) => Unit): Catch[Nothing] = {
+ new Catch(nothingCatcher, Some(new Finally(setter(oldVal)))) {
+ override def apply[U](body: => U): U = {
+ setter(newVal)
+ super.apply(body)
+ }
+ }
+ }
+
/** Creates a Catch object which unwraps any of the supplied exceptions. */
def unwrapping[T](exceptions: Class[_]*): Catch[T] = {
def unwrap(x: Throwable): Throwable =