-
Notifications
You must be signed in to change notification settings - Fork 508
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
Change IO's run-loop to encode error handlers #46
Conversation
Codecov Report
@@ Coverage Diff @@
## master #46 +/- ##
==========================================
+ Coverage 86.94% 87.91% +0.97%
==========================================
Files 17 17
Lines 268 273 +5
Branches 10 20 +10
==========================================
+ Hits 233 240 +7
+ Misses 35 33 -2 |
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.
This looks really fantastic. Would you mind adding a couple more AndThenTests
though? I think the test coverage here is probably alright, but it's through IO
. If only for documentation reasons, having some of these edge cases tested directly on AndThen
would be nice.
Very clever trick though. Obvious in hindsight.
var continue = true | ||
|
||
@inline def processRight(f: (Any) => Any): Unit = |
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.
This is probably actually faster if we don't inline in the bytecode, and HotSpot is allowed to do its thing due to the byte size of the body.
@djspiewak will do, tomorrow :-) |
Changes:
|
@@ -44,14 +44,14 @@ private[effect] sealed abstract class AndThen[-A, +B] extends Product with Seria | |||
var hasSuccessRef = isSuccess | |||
var continue = true | |||
|
|||
def processRight(f: (Any) => Any): Unit = | |||
def processSuccess(f: (Any) => Any): Unit = |
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'm 👍 on this, but I want to hear from @mpilquist before merging. If he gives it the thumbs up, I'll bring it in. I'm pretty excited about this too, since I suspect it'll make |
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.
👍 Looks great!
@@ -135,7 +141,17 @@ sealed abstract class IO[+A] { | |||
* | |||
* @see [[IO.raiseError]] | |||
*/ | |||
def attempt: IO[Either[Throwable, A]] | |||
def attempt: IO[Either[Throwable, A]] = { | |||
val fe = AndThen((a: A) => Pure(Right(a)), e => Pure(Left(e))) |
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.
Avoid constructing this in Pure
and RaiseError
cases? E.g., change to def
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.
What do you mean?
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.
Change val fe = ...
to def fe = ...
to avoid constructing a new AndThen
and then not using it in the Pure
and RaiseError
cases below.
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.
Oh right! Github cut off the diff so I couldn't see. I'll make that change on merge.
|
||
class AndThenTests extends FunSuite with Matchers { | ||
class AndThenTests extends FunSuite with Matchers with Checkers { |
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.
Minor thing: I prefer GeneratorDrivenPropertyChecks
and using matchers in forAll
instead of switching to the boolean assertion style. Not suggesting changing this though.
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.
Oh is that how you use matchers in properties? I was wondering. I miss Specs2. :-(
I discovered a weird space leak that I talked about in #42 (comment) by debugging the behavior of this law:
This PR fixes this space leak by changing the behavior of
IO#attempt
:AndThen.ShortCircuit
logicAndThen.ErrorHandler
, which is meant to process errorsAndThen
implementation we discardSingle
references until we reach anErrorHandler
that can process our error, or until we've got no moreAndThen
nodes to process, in which case we rethrow the error ... this is basically how Java's call-stack also worksThis implementation also opens up the possibility of a more optimized
handleErrorWith
, since now we don't necessarily needattempt.flatMap
to express it.