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

Await.result should work #186

Closed
lihaoyi opened this Issue Jan 30, 2014 · 8 comments

Comments

Projects
None yet
4 participants
@lihaoyi
Copy link
Contributor

lihaoyi commented Jan 30, 2014

import concurrent.duration._
Await.result(Future(1), 10 seconds)

This results in

TypeError: Cannot find function java_lang_Thread in object [object Object].

It should probably just be an alias for Future.get in ScalaJS since we can't block. That would save manually writing Future wrappers which do the same thing anyway in order to get code cross-compiling on JS/JVM.

@lihaoyi

This comment has been minimized.

Copy link
Contributor

lihaoyi commented Jan 30, 2014

It's be kind of weird to just ignore the duration and basically timeout immediately if the Future is not ready. On the other hand, that is probably the best you can do in ScalaJS for 99% of use cases, since anything else would need to be non-blocking. In particular, when creating Futures using a runNow ExecutionContext (probably pretty common), this will always pass since the Future will finish before returning, which is very nice.

@sjrd

This comment has been minimized.

Copy link
Member

sjrd commented Jan 30, 2014

I'll use my right as author to veto here, and say: no.
await should not work. The compiler could emit a compile error if we try to call it, but I do not want Scala.js to try and emulate that one. The very existence of this method is a workaround to be able to call blocking Java system APIs. There are no such thing as blocking JS system APIs, so this method should not work.

@lihaoyi

This comment has been minimized.

Copy link
Contributor

lihaoyi commented Jan 31, 2014

Sure, it's weird to have things be blocking, but...

Allowing people to use "blocking" internally allows some very elegant re-use. In particular, it allows you to re-use the same code for synchronous and asynchronous algorithms, just by swapping out the ExecutionContext!

  • Use a JSExecutionContext.Implicits.queued if you want an asynchronous run, and
  • a JSExecutionContext.Implicits.runNow together with await if you want a synchronous one.

That lets you cover both synchronous (returns T) and asynchronous (Future[T]) versions of a function def f(...): T in both JVM and JS, just by changing the execution context!

JVM JS
Blocking Any ExecutionContext + Await JSExecutionContext.Implicits.runNow + Await
Non-Blocking Any ExecutionContext Any ExecutionContext

On the other hand, if we insist that we shan't use Await on ScalaJS, you end up with a weird hole in the top right corner of the above table which can only be fixed by coding up your whole algorithm twice: once for synchrony once for asynchrony! Or... writing your own wrapper for Await that you can use internally to let your synchronous call delegate to your non-blocking code with a runNow ExecutionContext, allowing you to re-use big blobs of future-related code for your

I don't feel super strongly since I just wrote my own wrapper for the time being. I do think that JS/JVM Sync/Async code re-use is valuable. On the other hand, taking Await.result(f, time) and ignoring the time parameter is lying to the caller, breaching contract (we may go to jail!).

I'll leave it to you to decide and close this issue =)

@gzm0

This comment has been minimized.

Copy link
Contributor

gzm0 commented Jan 31, 2014

I see how this can be useful for some functions that are written in async style. However, it is a rather unsafe thing to do.

Consider what should happen, when you call Await on a Future that results from an Ajax call. In a similar scenario in Java, the thread would be parked until the result becomes available using a monitor construct or something.

In JavaScript, what can you do? In order to even receive the callback, you have to give back control to the event loop. But you cannot do that (without static re-writing). Therefore, even if you do the worst-of-all busy wait, you will not see that your Ajax call has terminated.

My suggestion is to use Scala.async for the cases where you want to write procedural style:

async {
  val x = ... // calculate something
  val y = await(ajaxCall(x))
  f(y)
}

will get rewritten (by macro) into something complicated, roughly equivalent to:

{
  val x = ... // calculate something
  val y = ajaxCall(x)
  y map { y => f(y) }
}

But yes, the bottom line is: If you are in async regime and you don't have threads, there is no going back.

@gzm0

This comment has been minimized.

Copy link
Contributor

gzm0 commented Feb 3, 2014

@sjrd @lihaoyi Can we close this? How do we proceed on this?

@sjrd

This comment has been minimized.

Copy link
Member

sjrd commented Feb 3, 2014

It should be closed, IMO.

@lihaoyi

This comment has been minimized.

Copy link
Contributor

lihaoyi commented Feb 3, 2014

Closing it =) I'll keep using my own wrapper for now

@lihaoyi lihaoyi closed this Feb 3, 2014

@SemanticBeeng

This comment has been minimized.

Copy link

SemanticBeeng commented Feb 19, 2015

May I see your (code :-) wrapper please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment