diff options
author | Paul Phillips <paulp@improving.org> | 2010-04-11 22:24:21 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-04-11 22:24:21 +0000 |
commit | bf3e7d490048f3b5d07a739e1283ac47173036a5 (patch) | |
tree | cb78f3dccdda2a3ff2f7818a1b25b191eb0c54a9 /src/library | |
parent | ebe772d693c6957c041d1be58dfd6f7686c2645b (diff) | |
download | scala-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.scala | 142 |
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 = |