@@ -42,8 +42,17 @@ trait MonadError[F[_]] {
4242 case Failure (e) => error(e)
4343 }
4444
45+ /** Deprecated method which doesn't work properly when constructing the `f` effect itself throws exceptions - the
46+ * finalizer `e` is not run in that case. Use `ensure2` instead, which uses a lazy-evaluated by-name parameter.
47+ */
48+ @ deprecated(message = " Use ensure2 for proper exception handling" , since = " 1.5.0" )
4549 def ensure [T ](f : F [T ], e : => F [Unit ]): F [T ]
4650
51+ /** Runs `f`, and ensures that `e` is always run afterwards, regardless of the outcome. `e` is run even when `f`
52+ * throws exceptions during construction of the effect.
53+ */
54+ def ensure2 [T ](f : => F [T ], e : => F [Unit ]): F [T ] = ensure(f, e)
55+
4756 def blocking [T ](t : => T ): F [T ] = eval(t)
4857}
4958
@@ -62,7 +71,7 @@ object syntax {
6271 def map [B ](f : A => B )(implicit ME : MonadError [F ]): F [B ] = ME .map(r)(f)
6372 def flatMap [B ](f : A => F [B ])(implicit ME : MonadError [F ]): F [B ] = ME .flatMap(r)(f)
6473 def handleError [T ](h : PartialFunction [Throwable , F [A ]])(implicit ME : MonadError [F ]): F [A ] = ME .handleError(r)(h)
65- def ensure (e : => F [Unit ])(implicit ME : MonadError [F ]): F [A ] = ME .ensure (r, e)
74+ def ensure (e : => F [Unit ])(implicit ME : MonadError [F ]): F [A ] = ME .ensure2 (r, e)
6675 def flatTap [B ](f : A => F [B ])(implicit ME : MonadError [F ]): F [A ] = ME .flatTap(r)(f)
6776 }
6877
@@ -98,13 +107,24 @@ object EitherMonad extends MonadError[Either[Throwable, *]] {
98107 case _ => rt
99108 }
100109
101- override def ensure [T ](f : Either [Throwable , T ], e : => Either [Throwable , Unit ]): Either [Throwable , T ] = {
110+ override def ensure [T ](f : Either [Throwable , T ], e : => Either [Throwable , Unit ]): Either [Throwable , T ] = ensure2(f, e)
111+
112+ override def ensure2 [T ](f : => Either [Throwable , T ], e : => Either [Throwable , Unit ]): Either [Throwable , T ] = {
102113 def runE =
103114 Try (e) match {
104115 case Failure (f) => Left (f)
105116 case Success (v) => v
106117 }
107- f match {
118+
119+ val ef =
120+ try f
121+ catch {
122+ case t : Throwable =>
123+ runE
124+ throw t
125+ }
126+
127+ ef match {
108128 case Left (f) => runE.right.flatMap(_ => Left (f))
109129 case Right (v) => runE.right.map(_ => v)
110130 }
@@ -125,11 +145,22 @@ object TryMonad extends MonadError[Try] {
125145
126146 override def fromTry [T ](t : Try [T ]): Try [T ] = t
127147
128- override def ensure [T ](f : Try [T ], e : => Try [Unit ]): Try [T ] =
129- f match {
148+ override def ensure [T ](f : Try [T ], e : => Try [Unit ]): Try [T ] = ensure2(f, e)
149+
150+ override def ensure2 [T ](f : => Try [T ], e : => Try [Unit ]): Try [T ] = {
151+ val ef =
152+ try f
153+ catch {
154+ case t : Throwable =>
155+ e
156+ throw t
157+ }
158+
159+ ef match {
130160 case Success (v) => Try (e).flatten.map(_ => v)
131161 case Failure (f) => Try (e).flatten.flatMap(_ => Failure (f))
132162 }
163+ }
133164}
134165class FutureMonad (implicit ec : ExecutionContext ) extends MonadAsyncError [Future ] {
135166 override def unit [T ](t : T ): Future [T ] = Future .successful(t)
@@ -155,16 +186,23 @@ class FutureMonad(implicit ec: ExecutionContext) extends MonadAsyncError[Future]
155186 p.future
156187 }
157188
158- override def ensure [T ](f : Future [T ], e : => Future [Unit ]): Future [T ] = {
189+ override def ensure [T ](f : Future [T ], e : => Future [Unit ]): Future [T ] = ensure2(f, e)
190+
191+ override def ensure2 [T ](f : => Future [T ], e : => Future [Unit ]): Future [T ] = {
159192 val p = Promise [T ]()
160193 def runE =
161194 Try (e) match {
162195 case Failure (f) => Future .failed(f)
163196 case Success (v) => v
164197 }
165- f.onComplete {
166- case Success (v) => runE.map(_ => v).onComplete(p.complete(_))
167- case Failure (f) => runE.flatMap(_ => Future .failed(f)).onComplete(p.complete(_))
198+ try {
199+ f.onComplete {
200+ case Success (v) => runE.map(_ => v).onComplete(p.complete(_))
201+ case Failure (f) => runE.flatMap(_ => Future .failed(f)).onComplete(p.complete(_))
202+ }
203+ } catch {
204+ case t : Throwable =>
205+ e.onComplete(_ => p.complete(Failure (t)))
168206 }
169207 p.future
170208 }
@@ -181,7 +219,8 @@ object IdentityMonad extends MonadError[Identity] {
181219 h : PartialFunction [Throwable , Identity [T ]]
182220 ): Identity [T ] = rt
183221 override def eval [T ](t : => T ): Identity [T ] = t
184- override def ensure [T ](f : Identity [T ], e : => Identity [Unit ]): Identity [T ] =
222+ override def ensure [T ](f : Identity [T ], e : => Identity [Unit ]): Identity [T ] = ensure2(f, e)
223+ override def ensure2 [T ](f : => Identity [T ], e : => Identity [Unit ]): Identity [T ] =
185224 try f
186225 finally e
187226}
0 commit comments