Skip to content

Commit 7d206f3

Browse files
committed
Added first cut of Try type, refactored from twitter util.
1 parent 9e7bbed commit 7d206f3

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed

src/library/scala/util/Try.scala

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/* __ *\
2+
** ________ ___ / / ___ Scala API **
3+
** / __/ __// _ | / / / _ | (c) 2008-2011, LAMP/EPFL **
4+
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5+
** /____/\___/_/ |_/____/_/ | | **
6+
** |/ **
7+
\* */
8+
9+
10+
11+
package scala.util
12+
13+
/**
14+
* The Try type represents a computation that may either result in an exception,
15+
* or return a success value. It's analagous to the `Either` type.
16+
*
17+
*/
18+
sealed abstract class Try[+T] {
19+
/**
20+
* Returns true if the Try is a Failure, false otherwise.
21+
*/
22+
def isFailure: Boolean
23+
24+
/**
25+
* Returns true if the Try is a Success, false otherwise.
26+
*/
27+
def isSuccess: Boolean
28+
29+
/**
30+
* Returns the value from this Success or the given argument if this is a Failure.
31+
*/
32+
def getOrElse[U >: T](default: => U) = if (isSuccess) apply() else default
33+
34+
/**
35+
* Returns the value from this Success or throws the exception if this is a Failure
36+
*/
37+
def apply(): T
38+
39+
/**
40+
* Returns the value from this Success or throws the exception if this is a Failure.
41+
* Alias for apply()
42+
*/
43+
def get = apply()
44+
45+
/**
46+
* Applies the given function f if this is a Result.
47+
*/
48+
def foreach[U](f: T => U) { onSuccess(f) }
49+
50+
/**
51+
* Returns the given function applied to the value from this Success or returns this if this is a Failure.
52+
*
53+
*/
54+
def flatMap[U](f: T => Try[U]): Try[U]
55+
56+
/**
57+
* Maps the given function to the value from this Success or returns this if this is a Failure
58+
*/
59+
def map[U](f: T => U): Try[U]
60+
61+
/**
62+
* Converts this to a Failure if the predicate is not satisfied.
63+
*/
64+
def filter(p: T => Boolean): Try[T]
65+
66+
/**
67+
* Calls the exceptionHandler with the exception if this is a Failure. This is like flatMap for the exception.
68+
*/
69+
def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U]
70+
71+
/**
72+
* Calls the exceptionHandler with the exception if this is a Failure. This is like map for the exception.
73+
*/
74+
def handle[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U]
75+
76+
/**
77+
* Invoked only if the computation was successful.
78+
*/
79+
def onSuccess[U](f: T => U): Try[T]
80+
81+
/**
82+
* Invoked only if the computation failed.
83+
*/
84+
def onFailure[U](rescueException: Throwable => U): Try[T]
85+
86+
/**
87+
* Invoked regardless of whether the computation completed
88+
* successfully or unsuccessfully. Implemented in terms of
89+
* `respond` so that subclasses control evaluation order. Returns a
90+
* chained `this` as in `respond`.
91+
*/
92+
def ensure[U](f: => U): Try[T] =
93+
respond { _ => f }
94+
95+
/**
96+
* Returns None if this is a Failure or a Some containing the value if this is a Success
97+
*/
98+
def toOption = if (isSuccess) Some(apply()) else None
99+
100+
/**
101+
* Invokes the given closure when the value is available. Returns
102+
* another 'This[R]' that is guaranteed to be available only *after*
103+
* 'k' has run. This enables the enforcement of invocation ordering.
104+
*
105+
* This is overridden by subclasses.
106+
*/
107+
def respond[U](k: Try[T] => U): Try[T] = {
108+
k(this)
109+
this
110+
}
111+
112+
/**
113+
* Invokes the given transformation when the value is available,
114+
* returning the transformed value. This method is like a combination
115+
* of flatMap and rescue. This method is typically used for more
116+
* imperative control-flow than flatMap/rescue which often exploits
117+
* the Null Object Pattern.
118+
*
119+
* This is overridden by subclasses.
120+
*/
121+
def transform[U](f: Try[T] => Try[U]): Try[U] =
122+
f(this)
123+
124+
/**
125+
* Returns the given function applied to the value from this Success or returns this if this is a Failure.
126+
* Alias for flatMap
127+
*/
128+
def andThen[U](f: T => Try[U]) = flatMap(f)
129+
130+
/**
131+
* Transforms a nested Try, i.e., a Try of type `Try[Try[T]]`,
132+
* into an un-nested Try, i.e., a Try of type `Try[T]`
133+
*/
134+
def flatten[U](implicit ev: T <:< Try[U]): Try[U]
135+
}
136+
137+
final case class Failure[+T](e: Throwable) extends Try[T] {
138+
def isFailure = true
139+
def isSuccess = false
140+
def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = {
141+
try {
142+
if (rescueException.isDefinedAt(e)) rescueException(e) else this
143+
} catch {
144+
case e2 => Failure(e2)
145+
}
146+
}
147+
def apply(): T = throw e
148+
def flatMap[U](f: T => Try[U]): Try[U] = Failure[U](e)
149+
def flatten[U](implicit ev: T <:< Try[U]): Try[U] = Failure[U](e)
150+
def map[U](f: T => U): Try[U] = Failure[U](e)
151+
def filter(p: T => Boolean): Try[T] = this
152+
def onFailure[U](rescueException: Throwable => U): Try[T] = {
153+
rescueException(e)
154+
this
155+
}
156+
def onSuccess[U](f: T => U): Try[T] = this
157+
def handle[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] =
158+
if (rescueException.isDefinedAt(e)) {
159+
Try(rescueException(e))
160+
} else {
161+
this
162+
}
163+
}
164+
165+
final case class Success[+T](r: T) extends Try[T] {
166+
def isFailure = false
167+
def isSuccess = true
168+
def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = Success(r)
169+
def apply() = r
170+
def flatMap[U](f: T => Try[U]): Try[U] =
171+
try f(r)
172+
catch {
173+
case e => Failure(e)
174+
}
175+
def flatten[U](implicit ev: T <:< Try[U]): Try[U] = r
176+
def map[U](f: T => U): Try[U] = Try[U](f(r))
177+
def filter(p: T => Boolean): Try[T] =
178+
if (p(apply())) this
179+
else Failure(new NoSuchElementException("Predicate does not hold"))
180+
def onFailure[U](rescueException: Throwable => U): Try[T] = this
181+
def onSuccess[U](f: T => U): Try[T] = {
182+
f(r)
183+
this
184+
}
185+
def handle[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = this
186+
}
187+
188+
object Try {
189+
190+
def apply[T](r: => T): Try[T] = {
191+
try { Success(r) } catch {
192+
case e => Failure(e)
193+
}
194+
}
195+
196+
}

0 commit comments

Comments
 (0)