1

Correction: as follows from two answers, the problem looks to be specific to dart as C# implements Task.Wait allowing to achieve the desired effect. I would be grateful for any further information on the reasons why this is not possible in dart or how to achieve it there. I would be happy to close the question in its current form.


There are situations where it could make sense to have synchronous functions use asynchronous calls internally waiting for their completion before delivering the result. This is explicitly not allowed in both C# and Dart: anything that uses await must be marked as async (thus returning a future).

A simple example in Dart, but the same is valid for C#:

Disclaimer: this is not how I would do things, so do not suggest a "correct" solution of converting all methods to async; the code here is just to illustrate the question.

I have a fully asynchronous implementation of a generic wrapper for HTTP requests to some particular REST API. It does some login, authentication etc.:

class RequestProcessor {
     Future post(String path, [payload]) async {
          return request("POST", path, payload);
     }
}

I would like to implement a high-level user-facing API translating to requests to the REST-API. Some of those methods I'd like to have synchronous. This is what I would like and am not allowed to have:

class API {
    final RequestProcessor processor;

    API(this.processor);

    // this takes long and should be asynchronous, happy with a future (OK)
    Future getQueryResults(query) async {
        return await processor.post("/query", query);
    }

    // here I would prefer to have it synchronous (COMPILE ERROR)
    String getVersion() {
        return await processor.post("/version");
    }
}

Question: Why is this not allowed?

Oleg Sklyar
  • 9,834
  • 6
  • 39
  • 62
  • ask the language designers, not us. – Daniel A. White Oct 26 '15 at 10:55
  • 1
    Possible duplicate of [Why can I not await the return value from my async method?](http://stackoverflow.com/questions/32762861/why-can-i-not-await-the-return-value-from-my-async-method) – Henrik Oct 26 '15 at 10:58
  • That's exactly what the `async` keyword does: enable the `await` keyword. They could maybe have done without `async`, but that would cause ambiguities. This article explains the design reasons for it: http://blogs.msdn.com/b/ericlippert/archive/2010/11/11/whither-async.aspx – Dennis_E Oct 26 '15 at 11:03
  • In Dart async is async and stays async. There is nothing that can be done about it. – Günter Zöchbauer Oct 26 '15 at 11:11
  • 1
    I would like to understand the design decision behind it: why is this that way? Apparently C# can handle it. – Oleg Sklyar Oct 26 '15 at 11:14
  • @Oleg: C# cannot "handle it". There are a few different hacks to try to force it, but it's extremely unnatural and there's no one hack that works in every scenario. In particular, `Wait()` is a holdover from the parallel processing library and **should not** be used on asynchronous tasks. Bottom line is that a *future* represents a *future result*. You can't return a *future* result *now* (i.e., synchronously). – Stephen Cleary Oct 26 '15 at 12:57
  • @StephenCleary But you can return a future result as soon as it is available and you can wait until it is available. What am I missing? Just saw the correction: so it would work, but should not be used. If so, why? – Oleg Sklyar Oct 26 '15 at 13:00
  • @Oleg: In C#, `Wait()` is a [common cause of deadlocks](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). There's always a better solution. 99% of the time, the better solution is "make the calling code asynchronous". – Stephen Cleary Oct 26 '15 at 13:02

4 Answers4

4

It's a design choice. Dart is single-threaded - each synchronous function call will run to completion before allowing any other code to run. If you allow a synchronous function to block until a future is complete, then no other code will run and the future will never complete (because the code that would complete it can't run).

It is possible to have a system that allows other code to run while one synchronous function is blocked. That requires either having more than one active stack (parallel or not), or implicitly transforming the entire program to be async. Neither choice is great when you compile to JavaScript, so Dart did not try to do that.

lrn
  • 64,680
  • 7
  • 105
  • 121
  • The blocking story is clear: synchronous calls block. So the point is in being single-threaded really and this is what makes it different to C# which provides the synchronous Wait? – Oleg Sklyar Oct 26 '15 at 12:08
  • Yes, C# is already multi-threaded, so it's not a problem to block one thread. Dart is single-threaded (by necessity when it compiles to JavaScript, which is also single-threaded), so it can't block one thread without blocking the entire isolate. – lrn Oct 28 '15 at 07:43
3

The await is an asynchronous wait so it does not make sense to have it in a synchronous function. To be asynchronous the method needs to return when the awaited operation is initiated, whereas the synchronous method needs to run to completion.

You can use a synchronous wait instead, in which case your method does not need to be async. In C# you can do this by calling the Wait() method on the returned task.

NeddySpaghetti
  • 13,187
  • 5
  • 32
  • 61
  • in c# you can call `Wait()` do wait for the task to complete, perhaps there is something similar in dart. – NeddySpaghetti Oct 26 '15 at 11:04
  • It does not look as if there was a similar mechanism in dart, but it made me realize I did not know about that particular specifics of C#. Thanks. – Oleg Sklyar Oct 26 '15 at 11:42
2

Because waiting and returning a future is fundamentally different.

Returning a future frees the current thread and optionally schedules a continuation for later, waiting blocks the current thread.

For example, in a UI thread, returning a future is fine but waiting will cause the UI to hang, in a web server thread waiting will block the thread and prevent the web server from handling more request, etc.

It's even possible waiting for what should be an async operation will cause a deadlock.

.net provide Task.Wait for when you know waiting is fine, I don't know about dart - but this is not automatic (except for await inside catch clauses in async methods in C#)

Nir
  • 29,306
  • 10
  • 67
  • 103
  • I understand the reasons behind await very well, so that is not my question. Generally it looks it comes down to "why dart does not have analogue of C# Wait() or how this could be achieved"... – Oleg Sklyar Oct 26 '15 at 11:18
0

In Dart marking a function/method async tells the VM that it needs to rewrite the code before executing it. await doesn't change an async function to a sync one, the function is still async, it just allows nicer syntax than then(() { return ...then(() { return...})}) chains.

If you make an async call everything following is async, there is nothing you can do about it.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • His question was why does the equivalent not work in C#, I think. – Dan Oct 26 '15 at 10:56
  • 1
    Because async and non-async methods have substantially different semantics. Async methods are converted into a state machine, which allows the code to be 'resumed' (not the best word for this) after the async method completes. – Dan Oct 26 '15 at 11:00