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
Attempt to make DeferredK rerunnable #1157
Conversation
Re-enable no-memoization law and fix deferredK to follow it (mostly) Changes practically nothing from the public api
@@ -146,25 +143,25 @@ object MonadDeferLaws { | |||
df.flatMap { df }.flatMap { df }.equalUnderTheLaw(just(3), EQ) shouldBe true | |||
} | |||
|
|||
fun <F> MonadDefer<F>.stackSafetyOverRepeatedLeftBinds(iterations: Int = 5000, EQ: Eq<Kind<F, Int>>): Unit { | |||
fun <F> MonadDefer<F>.stackSafetyOverRepeatedLeftBinds(iterations: Int = 50000, EQ: Eq<Kind<F, Int>>): 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.
5k is enough to trigger a SO, 50k makes them too slow maybe.
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.
Done
@@ -127,13 +165,13 @@ fun <A> DeferredKOf<A>.unsafeRunSync(): A = | |||
runBlocking { await() } | |||
|
|||
fun <A> DeferredKOf<A>.runAsync(cb: (Either<Throwable, A>) -> DeferredKOf<Unit>): DeferredK<Unit> = | |||
DeferredK.invoke(scope(), Dispatchers.Unconfined, CoroutineStart.DEFAULT) { | |||
DeferredK.invoke(fix().scope(), Dispatchers.Unconfined, CoroutineStart.DEFAULT) { |
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.
Fix shouldn't be necessary here, scope()
is defined as an alias to fix().scope
atop of the file.
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.
👍
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.
LGTM, I like the approach of having two separate nodes. I need to recheck the name of the constructors to prevent exposing these nodes directly, and whether it allows @extension codegen work the way we want.
|
||
fun <A> raiseError(t: Throwable): DeferredK<A> = | ||
failed(t) | ||
|
||
fun <A> failed(t: Throwable): DeferredK<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.
squint why is this here? why do we need an alias?
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 know I wrote it, I cannot remember why.
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.
Other than providing a more intuitive constructor for those that have never used raiseError I don't see the point either :) I'll remove it for now
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.
@ extension gen should work because for it to be considered a wrapper it just requires to extend the wrapped type which in this case it does.
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.
Awesome work! @ extension gen should work because for it to be considered a wrapper it just requires to extend the wrapped type which in this case it does. Before we merge this we need examples in the actual kdoc if required to distinguish about the instantiation strategies. All the markdown pages will be moved to kdocs and we don't want to keep making them bigger when they are referring to data typed or type classes. Text and examples should be in the kdoc unless it's a tutorial
It's not really required to distinguish between instantiation strategies (only for .k(), all others will work fine if a user does not use a deferred from outside that deferredK). So I think a section in the docs for DeferredK would be enough there. I can (and probably will in the next hour or so) add some kdoc to the api methods of DeferredK with examples. But except for .k() I don't think its worth mentioning retry-ability every time. Edit: Nvm, I'll just add a note to the methods indicating if the result is rerunnable or not. |
Added only to methods that may need it, mainly methods creating an instance of DeferredK since that may produce unexpected results as in memoization
I added kdoc to the methods constructing DeferredK instances with added notes about it being re-runnable or not. Should all other methods (even map/flatMap) use kdoc as well? If so I'l add that as well. Otherwise if the docs are alright this should be done. :) |
EDIT: Oh, they're already hidden :D Could you please add one more override of invoke that works as |
You mean marking Wrapped and Generated as Internal? They are already afaik. Changed them to data classes as well now. Do data classes override equals and stuff from their parent? o.O If so I may need to add equals/hashCode to those. |
Don't make them into |
This reverts commit 46501bc.
Good thing git makes it nice and easy to revert stuff :) |
That and I'm good to merge :D |
@1Jajen1 yes ideally all methods are documented with at least one example and a brief description of what they do. We consider this extremely important and are trying to enforce it lately in all PRs to ensure new users have a good experience when visiting the Arrow documentation. Each one of your methods then will have a dedicated page like this one http://arrow-docs.s3-website-us-east-1.amazonaws.com/docs/apidocs/arrow-effects/arrow.effects.typeclasses/-bracket/bracket-case.html |
@raulraja Yeah I saw those, built it locally. The jekyll command took a while but worked out fine o.O @pakoito So like an invoke that takes a Deferred? As in a convenience method over |
The function signature is |
Added a lot of kdoc to almost all methods of DeferredK and the invoke constructor. Btw. can you give generics a different color, like orange or something, in the api docs? Would make it so much more readable :) |
@1Jajen1 yes, feel free to create an issue and assign it to @israelperezglez |
Failed by reaching a time limit ... :/ |
It's the number of libraries. As we move past 1.0 most of them will be in their own repository. Effects, streams, recursion schemes etc... we'll all be able to evolve differently and then the build times will be much smaller. In the mean-time, if you find areas where the build times can improve feel free to raise issues. |
I'll look into speeding up gradle somehow and what exactly takes how much time... Don't know if I find stuff to improve, but worth trying :) |
So the build itself consistently takes about 20 mins (15-18 on my laptop) with almost all time spent on tests (kapt is also pretty slow, but its nothing compared to the tests). |
Welp, I am out of ideas (or better out of ways to properly test/debug this)... |
I fixed ank memory problems in master a while back, did you merge since then? |
Yes. It reports memory usage to be arount 1.5GB. Some ideas I had, but could not test yet:
|
I can confirm (using visualvm) the reported memory usage to be the actual heap memory usage, but also that the process running ank is actually consuming up to 4-5 times that, which means stuff not on the heap is leaking. Although I have no idea what causes that. |
@@ -1,9 +1,10 @@ | |||
apply plugin: 'kotlin' |
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.
Is this a refactor or a merge? O.O
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.
Too fast again :)
Explained this below.
So I ended up not finding the reason why so much off-heap memory was used and resorted to rewriting ank to use It now consumes up to ~3GB memory at most. (Heap ~2GB, rest is probably memory mapped io) I ended up putting the changes on this branch to test it on travis as well, if this should be in a seperate pr please let me know and I'll revert that :) Either way please check if this code is correct or produces good ouput, I couldn't find differences from running ank on master but you never know 🙈 |
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.
The ank refactor is fine if it solves the memory issue for you but in whatever case we need to fix the nested Try
signatures. You don't need those if you already have a constrain in MonadThrow<F>
|
||
fun getFileCandidates(target: File): List<File> = | ||
getFileCandidatesImpl(target) | ||
fun createTargetDirectory(source: Path, target: Path): Kind<F, Try<Path>> |
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.
There is no point on having concrete Kind<F, Try<Path>
return type since they can just be Kind<F, Path>
given you already have in scope a constrain on MonadThrow<F>
. Why is the internal Try
needed? You may just call MF().raiseError
or use MF().catch { ... }
if you just need to control synchronous error control. We can make the entire set of ops return IO<A>
if you'd rather use an explicit concrete data type.
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.
Yeah, I kinda forgot when defining the algebra and then did not change it when implementing ...
Will do in a sec. Just removing a bunch of them should be fine since MonadDefer.delay
also catches errors.
I had the type as Kind<F, A>
because I was starting with only Monad as the constraint on F. That would make testing with something like an id interpreter nice. Now with MonadThrow this may not be valid anymore. (Although Try might be a good fit there)
Changed the signatures. (They really were kinda dumb...) At least the whole build gets done in like 35 mins now. That leaves about 15 mins leeway for new tests and more kdoc to process before something has to be done about builds again, and if the repo gets split before that it likely won't be a problem ever :)
Did you never get memory issues running it? o.O Maybe its a os or even openjdk specific thing then. |
No issues here and the latest in master is gonna push those to s3 instead of github pages because jekyll times out in github |
Soooooo...is anyone pushing this while the builds aren't broken and master is stable? :D |
This should be good to go. |
Codecov Report
@@ Coverage Diff @@
## master #1157 +/- ##
============================================
+ Coverage 42.93% 42.98% +0.04%
- Complexity 836 841 +5
============================================
Files 404 403 -1
Lines 11428 11443 +15
Branches 1276 1317 +41
============================================
+ Hits 4907 4919 +12
+ Misses 6130 6120 -10
- Partials 391 404 +13
Continue to review full report at Codecov.
|
Solves #1156 and maybe #1131
Re-enable no-memoization law and fix deferredK to follow it (if used correctly)
Changes practically nothing from the public api.
I'll add some info to the docs later because if used wrong it might produce unexpected results.
Should the methods in DeferredK (well the public ones) have api docs (runnable ones) as well?
@pakoito I have skipped the invoke constructor for Wrapped because its syntax conflicts with the other one too much (the compiler was only able to infer which one to choose after passing more and more arguments which defeats the point of default argumens there), one should just use the other one or
.k()
instead. (And going from() -> Deferred<A>
tosuspend () -> A
is trivial)