diff options
Diffstat (limited to 'src/library/scala/util')
-rw-r--r-- | src/library/scala/util/Either.scala | 4 | ||||
-rw-r--r-- | src/library/scala/util/Properties.scala | 4 | ||||
-rw-r--r-- | src/library/scala/util/Sorting.scala | 18 | ||||
-rw-r--r-- | src/library/scala/util/Try.scala | 148 | ||||
-rw-r--r-- | src/library/scala/util/control/Exception.scala | 212 | ||||
-rw-r--r-- | src/library/scala/util/control/NoStackTrace.scala | 6 | ||||
-rw-r--r-- | src/library/scala/util/control/TailCalls.scala | 2 | ||||
-rw-r--r-- | src/library/scala/util/matching/Regex.scala | 29 |
8 files changed, 302 insertions, 121 deletions
diff --git a/src/library/scala/util/Either.scala b/src/library/scala/util/Either.scala index 32b7ec4487..01da0c1ef2 100644 --- a/src/library/scala/util/Either.scala +++ b/src/library/scala/util/Either.scala @@ -11,8 +11,6 @@ package scala package util -import scala.language.implicitConversions - /** Represents a value of one of two possible types (a disjoint union.) * Instances of Either are either an instance of [[scala.util.Left]] or [[scala.util.Right]]. * @@ -68,7 +66,7 @@ import scala.language.implicitConversions * @version 1.0, 11/10/2008 * @since 2.7 */ -sealed abstract class Either[+A, +B] { +sealed abstract class Either[+A, +B] extends Product with Serializable { /** * Projects this `Either` as a `Left`. */ diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 7ea597eac9..a176748cd6 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -120,7 +120,7 @@ private[scala] trait PropertiesTrait { /** The default end of line character. */ - def lineSeparator = propOrElse("line.separator", "\n") + def lineSeparator = System.lineSeparator() /* Various well-known properties. */ def javaClassPath = propOrEmpty("java.class.path") @@ -148,6 +148,8 @@ private[scala] trait PropertiesTrait { // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110. /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */ def isMac = osName startsWith "Mac OS X" + /** Returns `true` iff the underlying operating system is a Linux distribution. */ + def isLinux = osName startsWith "Linux" /* Some runtime values. */ private[scala] def isAvian = javaVmName contains "Avian" diff --git a/src/library/scala/util/Sorting.scala b/src/library/scala/util/Sorting.scala index b4f965f69b..3bda7c0d39 100644 --- a/src/library/scala/util/Sorting.scala +++ b/src/library/scala/util/Sorting.scala @@ -45,7 +45,7 @@ object Sorting { /** Sort an array of Floats using `java.util.Arrays.sort`. */ def quickSort(a: Array[Float]): Unit = java.util.Arrays.sort(a) - + private final val qsortThreshold = 16 /** Sort array `a` with quicksort, using the Ordering on its elements. @@ -57,9 +57,9 @@ object Sorting { def inner(a: Array[K], i0: Int, iN: Int, ord: Ordering[K]): Unit = { if (iN - i0 < qsortThreshold) insertionSort(a, i0, iN, ord) else { - var iK = (i0 + iN) >>> 1 // Unsigned div by 2 + val iK = (i0 + iN) >>> 1 // Unsigned div by 2 // Find index of median of first, central, and last elements - var pL = + var pL = if (ord.compare(a(i0), a(iN - 1)) <= 0) if (ord.compare(a(i0), a(iK)) < 0) if (ord.compare(a(iN - 1), a(iK)) < 0) iN - 1 else iK @@ -140,9 +140,9 @@ object Sorting { } inner(a, 0, a.length, implicitly[Ordering[K]]) } - + private final val mergeThreshold = 32 - + // Ordering[T] might be slow especially for boxed primitives, so use binary search variant of insertion sort // Caller must pass iN >= i0 or math will fail. Also, i0 >= 0. private def insertionSort[@specialized T](a: Array[T], i0: Int, iN: Int, ord: Ordering[T]): Unit = { @@ -176,7 +176,7 @@ object Sorting { m += 1 } } - + // Caller is required to pass iN >= i0, else math will fail. Also, i0 >= 0. private def mergeSort[@specialized T: ClassTag](a: Array[T], i0: Int, iN: Int, ord: Ordering[T], scratch: Array[T] = null): Unit = { if (iN - i0 < mergeThreshold) insertionSort(a, i0, iN, ord) @@ -188,7 +188,7 @@ object Sorting { mergeSorted(a, i0, iK, iN, ord, sc) } } - + // Must have 0 <= i0 < iK < iN private def mergeSorted[@specialized T](a: Array[T], i0: Int, iK: Int, iN: Int, ord: Ordering[T], scratch: Array[T]): Unit = { // Check to make sure we're not already in order @@ -212,7 +212,7 @@ object Sorting { // Don't need to finish a(i) because it's already in place, k = i } } - + // Why would you even do this? private def booleanSort(a: Array[Boolean]): Unit = { var i = 0 @@ -235,7 +235,7 @@ object Sorting { // TODO: add upper bound: T <: AnyRef, propagate to callers below (not binary compatible) // Maybe also rename all these methods to `sort`. @inline private def sort[T](a: Array[T], ord: Ordering[T]): Unit = a match { - case _: Array[AnyRef] => + case _: Array[AnyRef] => // Note that runtime matches are covariant, so could actually be any Array[T] s.t. T is not primitive (even boxed value classes) if (a.length > 1 && (ord eq null)) throw new NullPointerException("Ordering") java.util.Arrays.sort(a, ord) diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index b0eae74043..3c8b21b03c 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -9,9 +9,7 @@ package scala package util -import scala.collection.Seq import scala.util.control.NonFatal -import scala.language.implicitConversions /** * The `Try` type represents a computation that may either result in an exception, or return a @@ -61,7 +59,7 @@ import scala.language.implicitConversions * @author based on Twitter's original implementation in com.twitter.util. * @since 2.10 */ -sealed abstract class Try[+T] { +sealed abstract class Try[+T] extends Product with Serializable { /** Returns `true` if the `Try` is a `Failure`, `false` otherwise. */ @@ -75,16 +73,11 @@ sealed abstract class Try[+T] { * * ''Note:'': This will throw an exception if it is not a success and default throws an exception. */ - def getOrElse[U >: T](default: => U): U = - if (isSuccess) get else default + def getOrElse[U >: T](default: => U): U /** Returns this `Try` if it's a `Success` or the given `default` argument if this is a `Failure`. */ - def orElse[U >: T](default: => Try[U]): Try[U] = - try if (isSuccess) this else default - catch { - case NonFatal(e) => Failure(e) - } + def orElse[U >: T](default: => Try[U]): Try[U] /** Returns the value from this `Success` or throws the exception if this is a `Failure`. */ @@ -108,6 +101,11 @@ sealed abstract class Try[+T] { def map[U](f: T => U): Try[U] /** + * Applies the given partial function to the value from this `Success` or returns this if this is a `Failure`. + */ + def collect[U](pf: PartialFunction[T, U]): Try[U] + + /** * Converts this to a `Failure` if the predicate is not satisfied. */ def filter(p: T => Boolean): Try[T] @@ -134,6 +132,7 @@ sealed abstract class Try[+T] { * collection" contract even though it seems unlikely to matter much in a * collection with max size 1. */ + @deprecatedInheritance("You were never supposed to be able to extend this class.", "2.12") class WithFilter(p: T => Boolean) { def map[U](f: T => U): Try[U] = Try.this filter p map f def flatMap[U](f: T => Try[U]): Try[U] = Try.this filter p flatMap f @@ -145,18 +144,18 @@ sealed abstract class Try[+T] { * Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`. * This is like `flatMap` for the exception. */ - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] + def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] /** * Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`. * This is like map for the exception. */ - def recover[U >: T](f: PartialFunction[Throwable, U]): Try[U] + def recover[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, U]): Try[U] /** * Returns `None` if this is a `Failure` or a `Some` containing the value if this is a `Success`. */ - def toOption: Option[T] = if (isSuccess) Some(get) else None + def toOption: Option[T] /** * Transforms a nested `Try`, ie, a `Try` of type `Try[Try[T]]`, @@ -173,13 +172,31 @@ sealed abstract class Try[+T] { /** Completes this `Try` by applying the function `f` to this if this is of type `Failure`, or conversely, by applying * `s` if this is a `Success`. */ - def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = - try this match { - case Success(v) => s(v) - case Failure(e) => f(e) - } catch { - case NonFatal(e) => Failure(e) - } + def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] + + /** + * Returns `Left` with `Throwable` if this is a `Failure`, otherwise returns `Right` with `Success` value. + */ + def toEither: Either[Throwable, T] + + /** + * Applies `fa` if this is a `Failure` or `fb` if this is a `Success`. + * If `fb` is initially applied and throws an exception, + * then `fa` is applied with this exception. + * + * @example {{{ + * val result: Try[Throwable, Int] = Try { string.toInt } + * log(result.fold( + * ex => "Operation failed with " + ex, + * v => "Operation produced value: " + v + * )) + * }}} + * + * @param fa the function to apply if this is a `Failure` + * @param fb the function to apply if this is a `Success` + * @return the results of applying the function + */ + def fold[U](fa: Throwable => U, fb: T => U): U } @@ -192,57 +209,60 @@ object Try { try Success(r) catch { case NonFatal(e) => Failure(e) } - } final case class Failure[+T](exception: Throwable) extends Try[T] { - def isFailure: Boolean = true - def isSuccess: Boolean = false - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = - try { - if (f isDefinedAt exception) f(exception) else this - } catch { - case NonFatal(e) => Failure(e) - } - def get: T = throw exception - def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]] - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = this.asInstanceOf[Try[U]] - def foreach[U](f: T => U): Unit = () - def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]] - def filter(p: T => Boolean): Try[T] = this - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = - try { - if (rescueException isDefinedAt exception) { - Try(rescueException(exception)) - } else this - } catch { - case NonFatal(e) => Failure(e) - } - def failed: Try[Throwable] = Success(exception) + override def isFailure: Boolean = true + override def isSuccess: Boolean = false + override def get: T = throw exception + override def getOrElse[U >: T](default: => U): U = default + override def orElse[U >: T](default: => Try[U]): Try[U] = + try default catch { case NonFatal(e) => Failure(e) } + override def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]] + override def flatten[U](implicit ev: T <:< Try[U]): Try[U] = this.asInstanceOf[Try[U]] + override def foreach[U](f: T => U): Unit = () + override def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = + try f(exception) catch { case NonFatal(e) => Failure(e) } + override def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]] + override def collect[U](pf: PartialFunction[T, U]): Try[U] = this.asInstanceOf[Try[U]] + override def filter(p: T => Boolean): Try[T] = this + override def recover[U >: T](@deprecatedName('rescueException) pf: PartialFunction[Throwable, U]): Try[U] = + try { if (pf isDefinedAt exception) Success(pf(exception)) else this } catch { case NonFatal(e) => Failure(e) } + override def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] = + try { if (pf isDefinedAt exception) pf(exception) else this } catch { case NonFatal(e) => Failure(e) } + override def failed: Try[Throwable] = Success(exception) + override def toOption: Option[T] = None + override def toEither: Either[Throwable, T] = Left(exception) + override def fold[U](fa: Throwable => U, fb: T => U): U = fa(exception) } final case class Success[+T](value: T) extends Try[T] { - def isFailure: Boolean = false - def isSuccess: Boolean = true - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = this - def get = value - def flatMap[U](f: T => Try[U]): Try[U] = - try f(value) - catch { - case NonFatal(e) => Failure(e) - } - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = value - def foreach[U](f: T => U): Unit = f(value) - def map[U](f: T => U): Try[U] = Try[U](f(value)) - def filter(p: T => Boolean): Try[T] = { + override def isFailure: Boolean = false + override def isSuccess: Boolean = true + override def get = value + override def getOrElse[U >: T](default: => U): U = get + override def orElse[U >: T](default: => Try[U]): Try[U] = this + override def flatMap[U](f: T => Try[U]): Try[U] = + try f(value) catch { case NonFatal(e) => Failure(e) } + override def flatten[U](implicit ev: T <:< Try[U]): Try[U] = value + override def foreach[U](f: T => U): Unit = f(value) + override def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = this flatMap s + override def map[U](f: T => U): Try[U] = Try[U](f(value)) + override def collect[U](pf: PartialFunction[T, U]): Try[U] = try { - if (p(value)) this + if (pf isDefinedAt value) Success(pf(value)) else Failure(new NoSuchElementException("Predicate does not hold for " + value)) - } catch { - case NonFatal(e) => Failure(e) - } - } - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = this - def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed")) + } catch { case NonFatal(e) => Failure(e) } + override def filter(p: T => Boolean): Try[T] = + try { + if (p(value)) this else Failure(new NoSuchElementException("Predicate does not hold for " + value)) + } catch { case NonFatal(e) => Failure(e) } + override def recover[U >: T](@deprecatedName('rescueException) pf: PartialFunction[Throwable, U]): Try[U] = this + override def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] = this + override def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed")) + override def toOption: Option[T] = Some(value) + override def toEither: Either[Throwable, T] = Right(value) + override def fold[U](fa: Throwable => U, fb: T => U): U = + try { fb(value) } catch { case NonFatal(e) => fa(e) } } diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala index 24c297a2fc..64f491d7f0 100644 --- a/src/library/scala/util/control/Exception.scala +++ b/src/library/scala/util/control/Exception.scala @@ -10,26 +10,139 @@ package scala package util package control -import scala.collection.immutable.List import scala.reflect.{ ClassTag, classTag } -import java.lang.reflect.InvocationTargetException import scala.language.implicitConversions - /** Classes representing the components of exception handling. - * Each class is independently composable. Some example usages: + * + * Each class is independently composable. + * + * This class differs from [[scala.util.Try]] in that it focuses on composing exception handlers rather than + * composing behavior. All behavior should be composed first and fed to a [[Catch]] object using one of the + * `opt`, `either` or `withTry` methods. Taken together the classes provide a DSL for composing catch and finally + * behaviors. + * + * === Examples === + * + * Create a `Catch` which handles specified exceptions. * {{{ * import scala.util.control.Exception._ * import java.net._ * * val s = "http://www.scala-lang.org/" - * val x1 = catching(classOf[MalformedURLException]) opt new URL(s) - * val x2 = catching(classOf[MalformedURLException], classOf[NullPointerException]) either new URL(s) + * + * // Some(http://www.scala-lang.org/) + * val x1: Option[URL] = catching(classOf[MalformedURLException]) opt new URL(s) + * + * // Right(http://www.scala-lang.org/) + * val x2: Either[Throwable,URL] = + * catching(classOf[MalformedURLException], classOf[NullPointerException]) either new URL(s) + * + * // Success(http://www.scala-lang.org/) + * val x3: Try[URL] = catching(classOf[MalformedURLException], classOf[NullPointerException]) withTry new URL(s) + * + * val defaultUrl = new URL("http://example.com") + * // URL(http://example.com) because htt/xx throws MalformedURLException + * val x4: URL = failAsValue(classOf[MalformedURLException])(defaultUrl)(new URL("htt/xx")) + * }}} + * + * Create a `Catch` which logs exceptions using `handling` and `by`. + * {{{ + * def log(t: Throwable): Unit = t.printStackTrace + * + * val withThrowableLogging: Catch[Unit] = handling(classOf[MalformedURLException]) by (log) + * + * def printUrl(url: String) : Unit = { + * val con = new URL(url) openConnection() + * val source = scala.io.Source.fromInputStream(con.getInputStream()) + * source.getLines.foreach(println) + * } + * + * val badUrl = "htt/xx" + * // Prints stacktrace, + * // java.net.MalformedURLException: no protocol: htt/xx + * // at java.net.URL.<init>(URL.java:586) + * withThrowableLogging { printUrl(badUrl) } + * + * val goodUrl = "http://www.scala-lang.org/" + * // Prints page content, + * // <!DOCTYPE html> + * // <html> + * withThrowableLogging { printUrl(goodUrl) } + * }}} + * + * Use `unwrapping` to create a `Catch` that unwraps exceptions before rethrowing. + * {{{ + * class AppException(cause: Throwable) extends RuntimeException(cause) + * + * val unwrappingCatch: Catch[Nothing] = unwrapping(classOf[AppException]) + * + * def calcResult: Int = throw new AppException(new NullPointerException) + * + * // Throws NPE not AppException, + * // java.lang.NullPointerException + * // at .calcResult(<console>:17) + * val result = unwrappingCatch(calcResult) + * }}} + * + * Use `failAsValue` to provide a default when a specified exception is caught. + * + * {{{ + * val inputDefaulting: Catch[Int] = failAsValue(classOf[NumberFormatException])(0) + * val candidatePick = "seven" // scala.io.StdIn.readLine() + * + * // Int = 0 + * val pick = inputDefaulting(candidatePick.toInt) + * }}} + * + * Compose multiple `Catch`s with `or` to build a `Catch` that provides default values varied by exception. + * {{{ + * val formatDefaulting: Catch[Int] = failAsValue(classOf[NumberFormatException])(0) + * val nullDefaulting: Catch[Int] = failAsValue(classOf[NullPointerException])(-1) + * val otherDefaulting: Catch[Int] = nonFatalCatch withApply(_ => -100) + * + * val combinedDefaulting: Catch[Int] = formatDefaulting or nullDefaulting or otherDefaulting + * + * def p(s: String): Int = s.length * s.toInt + * + * // Int = 0 + * combinedDefaulting(p("tenty-nine")) + * + * // Int = -1 + * combinedDefaulting(p(null: String)) + * + * // Int = -100 + * combinedDefaulting(throw new IllegalStateException) + * + * // Int = 22 + * combinedDefaulting(p("11")) * }}} * - * This class differs from `scala.util.Try` in that it focuses on composing exception handlers rather than - * composing behavior. All behavior should be composed first and fed to a `Catch` object using one of the - * `opt` or `either` methods. + * @groupname composition-catch Catch behavior composition + * @groupprio composition-catch 10 + * @groupdesc composition-catch Build Catch objects from exception lists and catch logic + * + * @groupname composition-finally Finally behavior composition + * @groupprio composition-finally 20 + * @groupdesc composition-finally Build Catch objects from finally logic + * + * @groupname canned-behavior General purpose catch objects + * @groupprio canned-behavior 30 + * @groupdesc canned-behavior Catch objects with predefined behavior. Use combinator methods to compose additional behavior. + * + * @groupname dsl DSL behavior composition + * @groupprio dsl 40 + * @groupdesc dsl Expressive Catch behavior composition + * + * @groupname composition-catch-promiscuously Promiscuous Catch behaviors + * @groupprio composition-catch-promiscuously 50 + * @groupdesc composition-catch-promiscuously Useful if catching `ControlThrowable` or `InterruptedException` is required. + * + * @groupname logic-container Logic Containers + * @groupprio logic-container 60 + * @groupdesc logic-container Containers for catch and finally behavior. + * + * @define protectedExceptions `ControlThrowable` or `InterruptedException` * * @author Paul Phillips */ @@ -53,6 +166,7 @@ object Exception { /** !!! Not at all sure of every factor which goes into this, * and/or whether we need multiple standard variations. + * @return true if `x` is $protectedExceptions otherwise false. */ def shouldRethrow(x: Throwable): Boolean = x match { case _: ControlThrowable => true @@ -72,7 +186,9 @@ object Exception { override def toString() = name + "(" + desc + ")" } - /** A container class for finally code. */ + /** A container class for finally code. + * @group logic-container + */ class Finally private[Exception](body: => Unit) extends Described { protected val name = "Finally" @@ -85,6 +201,11 @@ object Exception { * 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. + * @tparam T result type of bodies used in try and catch blocks + * @param pf Partial function used when applying catch logic to determine result value + * @param fin Finally logic which if defined will be invoked after catch logic + * @param rethrow Predicate on throwables determining when to rethrow a caught [[Throwable]] + * @group logic-container */ class Catch[+T]( val pf: Catcher[T], @@ -107,10 +228,12 @@ object Exception { } finally fin foreach (_.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) + /** Create a new Catch container from this object and the supplied finally body. + * @param body The additional logic to apply after all existing finally bodies + */ + def andFinally(body: => Unit): Catch[T] = { + val appendedFin = fin map(_ and body) getOrElse new Finally(body) + new Catch(pf, Some(appendedFin), rethrow) } /** Apply this catch logic to the supplied body, mapping the result @@ -119,13 +242,13 @@ object Exception { def opt[U >: T](body: => U): Option[U] = toOption(Some(body)) /** Apply this catch logic to the supplied body, mapping the result - * into Either[Throwable, T] - Left(exception) if an exception was caught, - * Right(T) otherwise. + * into `Either[Throwable, T]` - `Left(exception)` if an exception was caught, + * `Right(T)` otherwise. */ def either[U >: T](body: => U): Either[Throwable, U] = toEither(Right(body)) /** Apply this catch logic to the supplied body, mapping the result - * into Try[T] - Failure if an exception was caught, Success(T) otherwise. + * into `Try[T]` - `Failure` if an exception was caught, `Success(T)` otherwise. */ def withTry[U >: T](body: => U): scala.util.Try[U] = toTry(Success(body)) @@ -149,23 +272,30 @@ object Exception { final def nonFatalCatcher[T]: Catcher[T] = mkThrowableCatcher({ case NonFatal(_) => true; case _ => false }, throw _) final def allCatcher[T]: Catcher[T] = mkThrowableCatcher(_ => true, throw _) - /** The empty `Catch` object. */ + /** The empty `Catch` object. + * @group canned-behavior + **/ final val noCatch: Catch[Nothing] = new Catch(nothingCatcher) withDesc "<nothing>" - /** A `Catch` object which catches everything. */ + /** A `Catch` object which catches everything. + * @group canned-behavior + **/ final def allCatch[T]: Catch[T] = new Catch(allCatcher[T]) withDesc "<everything>" - /** A `Catch` object which catches non-fatal exceptions. */ + /** A `Catch` object which catches non-fatal exceptions. + * @group canned-behavior + **/ final def nonFatalCatch[T]: Catch[T] = new Catch(nonFatalCatcher[T]) withDesc "<non-fatal>" /** 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". + * rethrow the exceptions it catches, you will typically want to call `opt`, + * `either` or `withTry` 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. + * @group composition-catch */ def catching[T](exceptions: Class[_]*): Catch[T] = new Catch(pfFromExceptions(exceptions : _*)) withDesc (exceptions map (_.getName) mkString ", ") @@ -174,42 +304,56 @@ object Exception { /** 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. + * catch whatever you ask of it including $protectedExceptions. + * @group composition-catch-promiscuously */ 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. */ + /** Creates a `Catch` object which catches and ignores any of the supplied exceptions. + * @group composition-catch + */ def ignoring(exceptions: Class[_]*): Catch[Unit] = catching(exceptions: _*) withApply (_ => ()) - /** Creates a `Catch` object which maps all the supplied exceptions to `None`. */ + /** Creates a `Catch` object which maps all the supplied exceptions to `None`. + * @group composition-catch + */ 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. */ + /** Creates a `Catch` object which maps all the supplied exceptions to the given value. + * @group composition-catch + */ def failAsValue[T](exceptions: Class[_]*)(value: => T): Catch[T] = catching(exceptions: _*) withApply (_ => value) + class By[T,R](f: T => R) { + def by(x: T): R = f(x) + } + /** Returns a partially constructed `Catch` object, which you must give - * an exception handler function as an argument to `by`. Example: + * an exception handler function as an argument to `by`. + * @example * {{{ - * handling(ex1, ex2) by (_.printStackTrace) + * handling(classOf[MalformedURLException], classOf[NullPointerException]) by (_.printStackTrace) * }}} + * @group dsl */ - class By[T,R](f: T => R) { - def by(x: T): R = f(x) - } + // TODO: Add return type def handling[T](exceptions: Class[_]*) = { def fun(f: Throwable => T) = catching(exceptions: _*) withApply f new By[Throwable => T, Catch[T]](fun _) } - /** Returns a `Catch` object with no catch logic and the argument as `Finally`. */ + /** Returns a `Catch` object with no catch logic and the argument as the finally logic. + * @group composition-finally + */ def ultimately[T](body: => Unit): Catch[T] = noCatch andFinally body - /** Creates a `Catch` object which unwraps any of the supplied exceptions. */ + /** Creates a `Catch` object which unwraps any of the supplied exceptions. + * @group composition-catch + */ def unwrapping[T](exceptions: Class[_]*): Catch[T] = { def unwrap(x: Throwable): Throwable = if (wouldMatch(x, exceptions) && x.getCause != null) unwrap(x.getCause) diff --git a/src/library/scala/util/control/NoStackTrace.scala b/src/library/scala/util/control/NoStackTrace.scala index b33b6a18dd..3647af4ac3 100644 --- a/src/library/scala/util/control/NoStackTrace.scala +++ b/src/library/scala/util/control/NoStackTrace.scala @@ -14,6 +14,8 @@ package util.control * on a global basis via a system property wrapper in * [[scala.sys.SystemProperties]]. * + * @note Since JDK 1.7, a similar effect can be achieved with `class Ex extends Throwable(..., writableStackTrace = false)` + * * @author Paul Phillips * @since 2.8 */ @@ -26,7 +28,7 @@ trait NoStackTrace extends Throwable { object NoStackTrace { final def noSuppression = _noSuppression - // two-stage init to make checkinit happy, since sys.SystemProperties.noTraceSupression.value calls back into NoStackTrace.noSuppression + // two-stage init to make checkinit happy, since sys.SystemProperties.noTraceSuppression.value calls back into NoStackTrace.noSuppression final private var _noSuppression = false - _noSuppression = sys.SystemProperties.noTraceSupression.value + _noSuppression = sys.SystemProperties.noTraceSuppression.value } diff --git a/src/library/scala/util/control/TailCalls.scala b/src/library/scala/util/control/TailCalls.scala index 953d5b407e..c7fefb1eba 100644 --- a/src/library/scala/util/control/TailCalls.scala +++ b/src/library/scala/util/control/TailCalls.scala @@ -55,7 +55,7 @@ object TailCalls { case Done(a) => Call(() => f(a)) case c@Call(_) => Cont(c, f) // Take advantage of the monad associative law to optimize the size of the required stack - case c: Cont[a1, b1] => Cont(c.a, (x: a1) => c f x flatMap f) + case c: Cont[a1, b1] => Cont(c.a, (x: a1) => c.f(x) flatMap f) } /** Returns either the next step of the tailcalling computation, diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 6d3d015b1a..bd55fb5d04 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -182,6 +182,9 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * val namedYears = for (m <- namedDate findAllMatchIn dates) yield m group "year" * }}} * + * Group names supplied to the constructor are preferred to inline group names + * when retrieving matched groups by name. Not all platforms support inline names. + * * This constructor does not support options as flags, which must be * supplied as inline flags in the pattern string: `(?idmsux-idmsux)`. * @@ -578,6 +581,9 @@ object Regex { */ trait MatchData { + /** Basically, wraps a platform Matcher. */ + protected def matcher: Matcher + /** The source from which the match originated */ val source: CharSequence @@ -650,16 +656,25 @@ object Regex { private lazy val nameToIndex: Map[String, Int] = Map[String, Int]() ++ ("" :: groupNames.toList).zipWithIndex - /** Returns the group with given name. + /** Returns the group with the given name. + * + * Uses explicit group names when supplied; otherwise, + * queries the underlying implementation for inline named groups. + * Not all platforms support inline group names. * * @param id The group name * @return The requested group - * @throws NoSuchElementException if the requested group name is not defined + * @throws IllegalArgumentException if the requested group name is not defined */ - def group(id: String): String = nameToIndex.get(id) match { - case None => throw new NoSuchElementException("group name "+id+" not defined") - case Some(index) => group(index) - } + def group(id: String): String = ( + if (groupNames.isEmpty) + matcher group id + else + nameToIndex.get(id) match { + case Some(index) => group(index) + case None => matcher group id + } + ) /** The matched string; equivalent to `matched.toString`. */ override def toString = matched @@ -667,7 +682,7 @@ object Regex { /** Provides information about a successful match. */ class Match(val source: CharSequence, - private[matching] val matcher: Matcher, + protected[matching] val matcher: Matcher, val groupNames: Seq[String]) extends MatchData { /** The index of the first matched character. */ |