-
Notifications
You must be signed in to change notification settings - Fork 531
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
Add Async#asyncCheckAttempt
for #3087
#3091
Conversation
def asyncPoll[A]( | ||
k: (Either[Throwable, A] => Unit) => IO[Either[Option[IO[Unit]], A]]): IO[A] = { | ||
val body = new Cont[IO, A, A] { | ||
def apply[G[_]](implicit G: MonadCancel[G, Throwable]) = { (resume, get, lift) => | ||
G.uncancelable { poll => | ||
lift(k(resume)) flatMap { | ||
case Right(a) => G.pure(a) | ||
case Left(Some(fin)) => G.onCancel(poll(get), lift(fin)) | ||
case Left(None) => poll(get) | ||
} | ||
} | ||
} | ||
} | ||
|
||
IOCont(body, Tracing.calculateTracingEvent(k)) | ||
} |
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.
Sorry if I missed it—do we get an optimization be re-implementing this for IO
? Otherwise probably we can delegate to the Async
implementation?
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've added it because a) only tests for async
I've found were in IOSpec.scala
and b) IO has async & async_
reimplemented too (and only visible bonus is Tracking + IOCont). If that not a concern, I could delete it.
Maybe some law should be added to AsyncLaws instead? Like (F.asyncPool[A](k => F.pure(Right(a))) <* F.unit) <-> F.pure(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.
Ah right, thanks, I missed the Tracing
. Actually my main concern was that if we override the implementation in IO
, then the generic implementation in Async
is not being tested anywhere, since as you point out the only are were in IOSpec
.
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.
Well, it was this way before -- Async.async & Async.async_
a re-implemented in IO
almost word by word, so the status quo stays the same. :)
Anyway, I've added three more laws to AsyncLaws
about asyncPoll <-> (async, pure)
(hope they make some sense) and added some synthetic test for some 'basic' Async
variant based off IO
which reuses all method implementations in Async
itself.
Also, should docs for |
@armanbilge, do you have any insight why check may randomly flick? Yesterday it was IoAppSpec, not it is WorkerThreadNameSpec -- both should be unaffected by my changes. :( |
Darn, I just restarted CI for you. |
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 great! Thank you for taking this on, and I'm sorry it took me so long to review. Left some comments.
import scala.concurrent.ExecutionContext | ||
import scala.concurrent.duration._ | ||
|
||
class AsyncSpec extends BaseSpec with Discipline { |
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.
Why did this have to be pulled out?
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.
As @armanbilge mentioned above, Async
version of async_
(and new generic version of async
itself) was not tested anywhere, as IOSpec.scala only tests Async[IO]
instance that, in turn, uses redefined IO.async & IO.async_
.
They are almost literal copies of one another, but still -- as there is two methods in Async
that both should provide backward compatible generic implementations via asyncPoll
I've decided to pull out test spec for Async
itself.
The problem is that Async does not have any instances except for IO
, and IO
overrides most methods, so spec provides another Async
instance that only defines necessary abstract methods.
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 gotcha. Nice catch!
* @see | ||
* [[async]] for a simplified variant without an option for immediate result | ||
*/ | ||
def asyncPoll[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.
The one problem I see with the name is we already use the word Poll
for something quite different! This might be worth bikeshedding a bit to avoid user confusion.
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 don't think my English is good enough to provide a meaningful name, but after some thoughts there are my suggestions:
asyncAttempt/tryAsync
-- as in 'we'll try to schedule async operation but if results are already available, then so be it'. Both with 'error handling' connotations, sadly.resolve/resolveEventually
-- as in 'computed value will be resolved one way or another, right now or in future';registerAsyncCallback
-- intentionally enterprise-like name to emphasis that this is a low-level method likecont
.
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'll give this some thought and report back in a day or two! I actually rather like asyncAttempt
, but you're right it does have that negative "error" context.
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, did you had time to think about a name?
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.
Ah, I haven't! Thank you for the reminder. I'll get to this, I apologize.
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 think asyncCheckAttempt
is probably the best I can come up with. I agree with you that we don't necessarily want it to be a really concise name.
def asyncPoll[A]( | |
def asyncCheckAttempt[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.
Done.
@@ -62,22 +62,28 @@ import java.util.concurrent.atomic.AtomicReference | |||
trait Async[F[_]] extends AsyncPlatform[F] with Sync[F] with Temporal[F] { | |||
|
|||
/** | |||
* The asynchronous FFI. | |||
* The asynchronous FFI with option for immediate result. |
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 unify this with the IO.asyncCheckAttempt
scaladoc?
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.
Not sure that I understood you correctly, but I've tried to sync IO
and Async
async*
method descriptions with exception of 'real-world examples'.
Async#asyncPoll
for #3087Async#asyncCheckAttempt
for #3087
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.
Thank you!! This has been a very much appreciated effort.
Implementation of proposed utility method in
Async
for double-check registration. Also implemented inIO
itself and some tests.I've chosen
asyncPoll
as a name as method itself reminds me about Rust's Futurepoll
method with also returns computed result or provides waker to schedule another poll sometime later.