summaryrefslogtreecommitdiff
path: root/src/library/scala/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/library/scala/util')
-rw-r--r--src/library/scala/util/Either.scala4
-rw-r--r--src/library/scala/util/Properties.scala4
-rw-r--r--src/library/scala/util/Sorting.scala18
-rw-r--r--src/library/scala/util/Try.scala148
-rw-r--r--src/library/scala/util/control/Exception.scala212
-rw-r--r--src/library/scala/util/control/NoStackTrace.scala6
-rw-r--r--src/library/scala/util/control/TailCalls.scala2
-rw-r--r--src/library/scala/util/matching/Regex.scala29
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,
+ * // &lt;!DOCTYPE html&gt;
+ * // &lt;html&gt;
+ * 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(&lt;console&gt;: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. */