-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ported IO#ensuring (and renamed to avoid mass confusion) #1662
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1662 +/- ##
==========================================
+ Coverage 93.88% 93.88% +<.01%
==========================================
Files 246 246
Lines 4088 4091 +3
Branches 154 150 -4
==========================================
+ Hits 3838 3841 +3
Misses 250 250
Continue to review full report at Codecov.
|
* @see [[raiseError]] | ||
* @see [[handleErrorWith]] | ||
*/ | ||
def guarantee[A](fa: F[A], finalizer: F[Unit]): F[A] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add a test of some kind to this?
I mean, even adding a reimplementation of this code to the laws for MonadError along with an example exercising it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 on adding to law. maybe also add quick doctest as an example and to provide coverage for the syntax code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A law would be useless, since it would over-constrain implementations. The only useful overrides of guarantee
would be for implementations which have it as a structural primitive, but in that case guarantee
would not be equivalent to flatMap
composed with attempt
. So it would be a very round-about way of making the function final
and running a ton of redundant tests.
The right thing to do is add a test, but unlike MonadTest
, MonadErrorTest
doesn't currently exist. I'm all in favor of adding it, but this falls into the category of things that are somewhat harder to work on (since I have to figure out how all that stuff works). Incoming sometime in the next few days, hopefully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the MonadTests
, it's basically just a vanilla scalatests suite. It should be trivial to create a MonadErrorTest
class and just write regular scalatests tests for guarantee
in it.
Update: actually there is already a MonadErrorTest
it's called MonadErrorSuite
, we should probably rename it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@djspiewak If guarantee
is a structural primitive, it must still behave as flatMap
composed with attempt
, no? I don't see how anything otherwise could be the case. What is the difference between a law and a test in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of a situation where a datatype adds extra guarantees to guarantee
, meaning that it would have distinct semantics from flatMap
composed with attempt
. I certainly can't prove that this is impossible, so I wouldn't want to rule it out completely with a law.
In general, I feel like concrete convenience functions (like this one) should be tested with tests, not laws, especially when their behavior follows trivially from other laws.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to see tests here specified in terms of the "bracket problem" (see http://hackage.haskell.org/package/layers-0.1/docs/Documentation-Layers-Overview.html#g:9 and the next couple sections).
I am not convinced this belongs on MonadError. As we've discussed previously, a monad layer being able to return an error has nothing to do with the rest of the effects in the stack being able to halt the computation, which is what guarantee
exists to guarantee semantics for.
@djspiewak this won't guarantee the execution of the finalizer in the presence of an exception being thrown unless |
@ceedubs It doesn't guarantee anything about exceptions. In fact, most datatypes that form a |
@djspiewak I guess that I just think that |
I think |
@edmundnoble @djspiewak just to be clear, I agree that this shouldn't try to catch exceptions. I'm just saying we should help users realize that that's the case :) |
@ceedubs I'm ok with either |
@edmundnoble @johnynek @kailuowang Should be ready for a re-review. Tests added. |
@edmundnoble or @johnynek: Would one of you mind reviewing the current state of this PR and giving me a 👍 or 👎? I'd like to land this soon. |
I think this is pretty valuable and worthy of adding to the 1.0 milestone. What do you guys think? |
If we can add a test it seems fine to add to me.
On Fri, Nov 17, 2017 at 16:48 LukaJCB ***@***.***> wrote:
I think this is pretty valuable and worthy of adding to the 1.0 milestone.
What do you guys think?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1662 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAEJdvsyiaFsRiefYMdMlpcxM4zhH8Lwks5s3ilPgaJpZM4NYo0M>
.
--
P. Oscar Boykin, Ph.D. | http://twitter.com/posco | http://pobox.com/~boykin
|
This doesn't work with scala> val fin = OptionT.liftF(IO(Console.println("hi")))
fin: cats.data.OptionT[cats.effect.IO,Unit] = OptionT(IO$1731525909)
scala> (OptionT(IO(Option(1))) guarantee fin).value.unsafeRunSync
hi
res20: Option[Int] = Some(1)
scala> (OptionT(IO(Option.empty[Int])) guarantee fin).value.unsafeRunSync
res21: Option[Int] = None So I think we can't offer this combinator. I'm pretty convinced that it has to be a primitive. |
I see, that seems pretty reasonable. Maybe it could be part of the |
@tpolecat thanks, I think that your counterexample is a really important one. I'm going to go ahead and close this out, because I don't think that it satisfied the use-case that it was intended for. It seems like the discussion has continued in typelevel/cats-effect#88 . @djspiewak let me know if you disagree and think that this should be reconsidered. |
This function generalizes
finally
in thetry
/catch
/finally
triumvirate. Very much open to suggestions on the name. As a random note, isensure
even a useful function?Also closes #1630