From f10dcc76dff4aa9146cd1ec4052fe136f597a260 Mon Sep 17 00:00:00 2001 From: cchantep Date: Wed, 29 Oct 2014 17:25:01 +0100 Subject: SI-8336: add `fold` & `toEither` to `util.Try` `res.fold(fa, fb)` evaluates to `fa(e)` if `res` is a `Failure(e)`, or `fb(value)` if `res` is a `Success(value)`. (If `fb` throws an exception `e` when applied, `fa(e)`.) --- src/library/scala/util/Try.scala | 30 ++++++++++++++++++++++++++ test/files/jvm/try-type-tests.scala | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index 1e6ae6c591..c807677119 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -174,6 +174,31 @@ sealed abstract class Try[+T] extends Product with Serializable { * `s` if this is a `Success`. */ 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 + } object Try { @@ -208,6 +233,8 @@ final case class Failure[+T](exception: Throwable) extends Try[T] { 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) } @@ -236,4 +263,7 @@ final case class Success[+T](value: T) extends Try[T] { 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/test/files/jvm/try-type-tests.scala b/test/files/jvm/try-type-tests.scala index 962afbd30f..b3926020f0 100644 --- a/test/files/jvm/try-type-tests.scala +++ b/test/files/jvm/try-type-tests.scala @@ -118,6 +118,44 @@ trait TryStandard { assert(f.transform(succ, fail).get == 0) } + def testSuccessEither(): Unit = { + val t = Success(1) + assert(t.toEither.isRight) + } + + def testFailureEither(): Unit = { + val t = Failure(new Exception("foo")) + assert(t.toEither.isLeft) + } + + def testFoldSuccess(): Unit = { + val t = Success(1) + val res = t.fold("Throws " + _, "Returns " + _) + assert(res == "Returns 1") + } + + def testFoldFailure(): Unit = { + val t = Failure(new Exception("foo")) + val res = t.fold("Throws " + _, "Returns " + _) + assert(res == "Throws java.lang.Exception: foo") + } + + def testFoldSuccessFailure(): Unit = { + val t = Success(1) + val res = t.fold("Throws " + _, _ => throw new Exception("foo")) + assert(res == "Throws java.lang.Exception: foo") + } + + def testFoldFailureFailure(): Unit = { + val t = Failure(new Exception("foo")) + val res = try { + t.fold(_ => throw new Exception("bar"), "Returns " + _) + } catch { + case e: Throwable => "Throws " + e + } + assert(res == "Throws java.lang.Exception: bar") + } + testForeachSuccess() testForeachFailure() testFlatMapSuccess() @@ -136,6 +174,11 @@ trait TryStandard { testFailedFailure() testSuccessTransform() testFailureTransform() + testSuccessEither() + testFailureEither() + testFoldSuccess() + testFoldFailure() + testFoldSuccessFailure() } object Test -- cgit v1.2.3