Async/Await is a mess or a living hell

2,084 views
Skip to first unread message

Rat Jo

unread,
Mar 20, 2015, 4:48:18 AM3/20/15
to mi...@dartlang.org

Since I started to use async/await, my life have become hell. Here is some the few reason why:

dart:core-patch/object_patch.dart 42          Object._noSuchMethod
dart:core-patch/object_patch.dart 45          Object.noSuchMethod
package:async_await/src/xform.dart 854        AsyncTransformer._translateSynchronousForEach
package:async_await/src/xform.dart 892        AsyncTransformer.visitForEachStatement
package:analyzer/src/generated/ast.dart 7003  ForEachStatement.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit
- As soon as you add one await somewhere, your whole program transform in a await/async hell/mess where you have to add them to almost all of your function, because I'm trying to use indexeddb, so every time you want to access your data, it's a "await".
- If you want to use IndexedDb, you don't have much choose then to use async/await.
- Sometime, just marking some function async make the compiler throwing the towel and give crazy number of error. You have to change the error of function, split function, change variable name, etc.. to eventually get your code working...
- You make unittest program to test your website? all of your function start with an await


It's have been since async/await have been available that I started to use them which is now almost three month and those problem didn't go away, not even with the latest 1.9.0-dev.10.10 (rev 44550).

So, I got one suggestion, if you think about starting to use await/async, don't do it.

Günter Zöchbauer

unread,
Mar 20, 2015, 5:31:02 AM3/20/15
to mi...@dartlang.org
I don't see how this has to do with async/await.
If you use the old way you have "Future<xxx>" and "then(() => ...)" instead of "async" and "await".
This is how async programming is. Async is contagious no matter if you use the old or the new style.

Joao Pedrosa

unread,
Mar 20, 2015, 9:22:39 AM3/20/15
to mi...@dartlang.org
Hi,

async/await is one of those things that take a lot of time to mature. In this case it's not easy to be an early adopter. The Dart developers themselves are still understanding it and fixing the implementations as they go.

Microsoft may have poured $1 billion into their development tools to make things like async/await as transparent as possible. :-) But now Dart is adding those on a budget and even JavaScript is scheduled to get them eventually.

Async programming may complicate scaling the problem to sizable code bases. Without proper debugging features people don't want to complicate the solutions too much. The work that the tool developers put into making it more transparent is important to make debugging still reasonable.

The alternative is to try to keep the solution as small as possible for now. Even in Node.JS which is founded on async programming ideals it is still complicated for them, but they solve it by just keeping the solutions small enough. And they have  been working on more debugging tools.

Another alternative in Dart is should Fletch prove itself, then we could program in Dart with just process forking and mostly synchronous code.

I think we have followed the standards created by Microsoft for a long time. Something that Microsoft never did was to use a Unix subsystem like Apple did with their OSX. So idioms that worked well on Unix environments like process forking was never popular on Windows systems. But recently with Apple systems and Android, Unix has started to take on the client side and who knows maybe we can free ourselves from standards created by Microsoft some day. Until then async programming will still be important. :-)

Cheers,
Joao

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

Bob Nystrom

unread,
Mar 20, 2015, 12:41:33 PM3/20/15
to General Dart Discussion
On Fri, Mar 20, 2015 at 1:48 AM, Rat Jo <jora...@gmail.com> wrote:

Since I started to use async/await, my life have become hell. Here is some the few reason why:

dart:core-patch/object_patch.dart 42          Object._noSuchMethod
dart:core-patch/object_patch.dart 45          Object.noSuchMethod
package:async_await/src/xform.dart 854        AsyncTransformer._translateSynchronousForEach
package:async_await/src/xform.dart 892        AsyncTransformer.visitForEachStatement
package:analyzer/src/generated/ast.dart 7003  ForEachStatement.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit

This is a bug in the async_await compiler. Note that this is unrelated to the native implementations of async/await in the VM and dart2js. That compiler exists mainly as a temporary way to let us experiment with using async/await in Dart code before any native implementations of it existed.

If you're on the latest dev builds of the SDK, I encourage you to stop using the async_await compiler and just use the VM's and dart2js's native implementations of it. I'm not promising that they're bug-free either, but they are getting a lot more love and attention than the compiler is.
 
- As soon as you add one await somewhere, your whole program transform in a await/async hell/mess where you have to add them to almost all of your function, because I'm trying to use indexeddb, so every time you want to access your data, it's a "await".
- If you want to use IndexedDb, you don't have much choose then to use async/await.

This has nothing to do with async/await and everything to do with asynchrony in general. You had to do this before using Futures.
 
- Sometime, just marking some function async make the compiler throwing the towel and give crazy number of error. You have to change the error of function, split function, change variable name, etc.. to eventually get your code working...
- You make unittest program to test your website? all of your function start with an await

You don't need to—and shouldn't—await the test() calls themselves. Unittest will handle that for you. The test bodies, of course, do need to handle asynchrony. If you weren't using async/await here, you'd be doing a whole lot of future chaining.

If you're writing a lot of async tests, I encourage you to look at the scheduled_test package. It was designed exactly for this use case and makes this kind of code much clearer. It's what we use for all of pub's tests, which are highly asynchronous (and were written well before async/await existed).

So, I got one suggestion, if you think about starting to use await/async, don't do it.

You certainly have the option to not use the async/await syntax but in many cases (like using IndexedDb here), you can't opt out of being asynchronous. That API is async whether you like it or not. Async/await just makes it more palatable.

If you don't like asynchrony in general, I agree with you. Unfortunately, the world's JS engines don't. Since we have to compile to JS, our hands our tied on what kinds of concurrency primitives Dart can implement.

Cheers!

- bob
 


David Notik

unread,
Mar 21, 2015, 2:35:26 AM3/21/15
to mi...@dartlang.org
If you don't like asynchrony in general, I agree with you. Unfortunately, the world's JS engines don't. Since we have to compile to JS, our hands our tied on what kinds of concurrency primitives Dart can implement.

Curious as to what other kinds of concurrency primitives there are, and why you don't like asynchrony. Would like to learn more, and perhaps you can share some links...

Jim Trainor

unread,
Mar 21, 2015, 7:33:16 AM3/21/15
to mi...@dartlang.org

I tried async/await then backed away when dart2js threw it hands up.  When it's is ready I will try again, although I pretty much am totally used to the future model at this point.  The one improvement I'd like to see is better debugging so that a stack trace is somehow preserved across events (trace back to the origin of the completion). Maybe async/await will bring that or something similar? If so then I'd consider that large benefit.

Much of my async codes ends up as lists of simple functions, typically inner, that I execute using a small utility called "execAsyncOps".  I find this easy to understand and tidier than the future.then().then().then() pattern.  Especially, of course, when the list of operations becomes long.

Looks like this:

Future doSomethingAsync() {

 step_one(_) => do something;

 step_two(_) => do next thing;

 step_three(var resultOfStepTwo) => do some with resultOfStepTwo;

 step_four_final(_) => return finalValue;

 return execAsyncOps([step_one, step_two, step_three, step_four]);
}


Here is the execAsyncOps code:

typedef Future AsyncOp(var arg);

/**
  * Execute a list of chained async operations in order. Return the
  * future result of the last operation.
  */
Future execAsyncOps(List<AsyncOp> ops, {var firstOpParam : null}) {

 // If empty ops list then return a noop future.
  if (ops.length == 0) {
   
return new Future.sync(() {});
  }

 // Initialize by executing the first operation and making it into a future
 // if it is not already.

if (!(nextFuture is Future)) {

 var nextFuture = ops[0](firstOpParam);
 
if (!(nextFuture is Future)) {
  nextFuture
= new Future.value(nextFuture);
 
}

   // Iterate over the remaining futures in the list.
 
if (ops.length > 1) {
   
ops.sublist(1).forEach( (op) => nextFuture = nextFuture.then(op) );
  }

 // Return the last future value (the value returned by the last operation).
 
return nextFuture;
}

Jim Trainor

unread,
Mar 21, 2015, 7:35:46 AM3/21/15
to mi...@dartlang.org
fyi - there is an errant extra line of code ("if (!(nextFuture is Future)) {") in my last post. The google groups code editor has a lot of fight in it I find.

Günter Zöchbauer

unread,
Mar 21, 2015, 8:01:14 AM3/21/15
to mi...@dartlang.org
Do you use the stack_trace package?
While it's around for a long time I didn't stumble upon it until very recently
- http://stackoverflow.com/questions/29013591/how-to-get-the-full-stack-trace-for-async-execution
Would be great to have this stack trace available in the debugger as well.

Jim Trainor

unread,
Mar 21, 2015, 12:17:25 PM3/21/15
to mi...@dartlang.org
No I haven't used stack_trace.  I'll likely add it to my top level exception handler for error capture and reporting in the deployed application.  Should be natively supported by the dart debugger.  When I'm debugging an errant exception I am normally in a unit test.  The unit test package implements the top level exception handler and it doesn't report a full stack trace when an expect(...) fails. Maybe that's a place to integrate stack_trace.... or maybe I need to go look at my tests and understand better how it might be employed.


Need it in the debugger but default to be most useful.

Daniel Davidson

unread,
Mar 21, 2015, 12:38:18 PM3/21/15
to mi...@dartlang.org
is this the same?

     return Future.wait([step_one, step_two, step_three, step_four]);

Günter Zöchbauer

unread,
Mar 21, 2015, 12:56:48 PM3/21/15
to mi...@dartlang.org
This executes the steps in parallel and waits for all results.
Jims code seems to chain the futures so that one step is called only after the previous has finished.
Future.forEach executes one step after the other.

Günter Zöchbauer

unread,
Mar 21, 2015, 1:01:31 PM3/21/15
to mi...@dartlang.org
I agree, all these async stack frames are useless noise if you're not actually debugging how futures and zones work which I usually don't do.

You can create a helper to wrap each tests code with Chain capture.

stackTrace(void test()) {
 
Chain.capture(() => test(), onError: (error, stack) {
    _log
.shout(error);
    _log
.info(stack.terse);
 
});
}

void main() {
  initLogging
();

 
group('lib', () {

    test
('basic', () => stackTrace(() {
     
return new Future(() => someFunc());
   
}));
 
});
}

someFunc
() => new Future(()=> someOtherFunc());

someOtherFunc
() => new Future(() => expect(false, isTrue));

but maybe there are better ways.

Alex Tatumizer

unread,
Mar 21, 2015, 1:08:52 PM3/21/15
to mi...@dartlang.org
>     return Future.wait([step_one, step_two, step_three, step_four]);

No, Wait runs stuff in parallel. What you normally need is to pass result of previous step to the next one.
"Wait" doesn't do that.
BTW, there's a standard verb for operation that calls functions in a sequence, passing result of previous one: "fold" (aka: "reduce").
The difference is that in "fold" the same function gets called. We need the "next" function to be called.
In Futures API, there's also forEach, which calls same function for a series of values.
Many things are similar, just not what's needed in the most common case.

I think it would be good to add some method that implements the sequence of steps, without forcing programmer to write lots of "then".
Strange that we still don't have it.

Justin Fagnani

unread,
Mar 21, 2015, 1:12:17 PM3/21/15
to General Dart Discussion


On Mar 21, 2015 4:33 AM, "Jim Trainor" <jim.train...@gmail.com> wrote:
>
> I tried async/await then backed away when dart2js threw it hands up.  When it's is ready I will try again, although I pretty much am totally used to the future model at this point.

The model is exactly the same though. async/await is based on Futures.

>>> It's have been since async/await have been available that I started to use them which is now almost three month and those problem didn't go away, not even with the latest 1.9.0-dev.10.10 (rev 44550).
>>>
>>> So, I got one suggestion, if you think about starting to use await/async, don't do it.
>

Günter Zöchbauer

unread,
Mar 21, 2015, 1:12:22 PM3/21/15
to mi...@dartlang.org
You could use Future.forEach on a list of async function calls (same as Danies Future.wait example), no? 

Alex Tatumizer

unread,
Mar 21, 2015, 1:19:24 PM3/21/15
to mi...@dartlang.org
No. forEach calls the same function.
Is Proposal needed to petition for chain() function?

Günter Zöchbauer

unread,
Mar 21, 2015, 1:28:32 PM3/21/15
to mi...@dartlang.org
testForEach() {
var steps = [
() => someAsync(1),
() => someAsync(2),
() => someAsync(3),
() => someAsync(4)
];
Future.forEach(steps, (x) => x());
}

var rnd = new Random();

someAsync(int i) => new Future.delayed(
new Duration(milliseconds: rnd.nextInt(200)), () => print(i));

prints:
1
2
3
4

I don't see how to pass the results from one call to the next though.

kc

unread,
Mar 21, 2015, 2:35:35 PM3/21/15
to mi...@dartlang.org
On Saturday, March 21, 2015 at 6:35:26 AM UTC, David Notik wrote:
If you don't like asynchrony in general, I agree with you. Unfortunately, the world's JS engines don't. Since we have to compile to JS, our hands our tied on what kinds of concurrency primitives Dart can implement.

Curious as to what other kinds of concurrency primitives there are, and why you don't like asynchrony. Would like to learn more, and perhaps you can share some links...


Bob has a good post at his blog which highlights why Fletch with coroutines is so enticing:


K.

 

Jim Trainor

unread,
Mar 21, 2015, 4:49:52 PM3/21/15
to mi...@dartlang.org
Future.wait is used when you fire off many async operations that execute concurrently and wish to wait for all of them to finish.  
My variation is ordered sequential execution. Execute one, then two, then three.  My "execAsyncOps" function is exactly like calling future.then(step_one). then(step_two).then(step_three).... but tidier for long operation lists and easier to deal with when one is generating the operation list dynamically (of course, "tidier" and "easier" are IMO).

I use both Future.wait, ordinary future.then chains, and my execAsyncOps utility in my code . I find however that I much prefer execAsyncOps([firstOp, secondOp, thirdOp]) over firstOp.then(secondOp).then(thirdOp).  I only use the plain future.then() call for very simple cases (e.g. a single then) because the code becomes unreadable if it get's too long.

I have some code with very long operation lists (e.g. tens of steps).  Further, some of those individual steps are themselves executing yet more lists of async ops. It all works fine and the code is readable and fairly easy debug.


Here is an example of the look and feel of my real code so that you get an idea of readability once the async operations are broken down into bite size chunks and isolated in inner functions.  This code is gathering resources that could be fetched from an http server or could be fetched from an local cache (indexed_db) then performing a processing operation to build a summary then executing a javascript callback with the result. This function doesn't return a future but typically a function like this would return the future that is returned by the execAsyncOps call.

void getItemResourceSummary(int userid, String itemgroupid, int itemid, String profile, String lang, jsb.JsCallback callback) {


    irs.ItemResource fetchedItemResource;

    drs.DictResource fetchedDictResource;

    dprs.DictPrefResource fetchedDictPrefResource;


    _1_fetchItem(_) => _itemResourceService.get(new irs.ItemLocator(userid, itemgroupid, itemid, lang));


    _2_receiveItem(irs.ItemResource resource) => fetchedItemResource = resource;


    _3_fetchDict(_) => _dictResourceService.get(new drs.DictLocator(fetchedItemResource.queryResult.dictid, lang));


    _4_receiveDict(drs.DictResource resource) => fetchedDictResource = resource;


    _5_fetchDictPref(_) => _dictPrefResourceService.get(new dprs.DictPrefLocator(fetchedItemResource.queryResult.dictid, profile, lang));


    _6_receiveDictPref(dprs.DictPrefResource dictPrefResource) => fetchedDictPrefResource = dictPrefResource;


    _7_makeSummary(_) => new wbm_bldr.JsonItem.fromResources(fetchedDictResource.queryResult, fetchedDictPrefResource.queryResult, fetchedItemResource.queryResult);


    _8_executeCallback(wbm_bldr.JsonItem summary) => callback([summary]);


    more_async.execAsyncOps(

      [_1_fetchItem, _2_receiveItem, _3_fetchDict, _4_receiveDict, _5_fetchDictPref, _6_receiveDictPref, _7_makeSummary, _8_executeCallback]

    );

  }


--

Jim Trainor

unread,
Mar 21, 2015, 4:55:35 PM3/21/15
to mi...@dartlang.org
I'll add that what would be a mess and a living hell would be trying to do something with the same amount of code, and the same level of complexity, in Javascript!

Sorry, I couldn't resist :)

Jim Trainor

unread,
Mar 21, 2015, 5:16:59 PM3/21/15
to mi...@dartlang.org
Indeed my example might be exactly the same as Future.forEach.  I'd have to study to be sure.  Not sure when forEach appeared versus when I did mine. Maybe I missed it or I rolled my own before it appeared.... not sure.  My variation has to option of passing in the first async op parameter to kick off the processing.  Just a nicety.  I know also that I've had to tweak mine over time to property deal with indexed_db interactions (indexed_db closes the transaction when you leave the event loop without an db operation outstanding. It's easy to do by accident so one must be careful. Further the behaviour varies between browsers so it's nice stay in control...).

Alex Tatumizer

unread,
Mar 21, 2015, 7:02:49 PM3/21/15
to mi...@dartlang.org
Both Future and Stream APIs improved a lot over time. No advertisement is ever made for these improvements.
Future.chain([f1, f2,...fn]) is still sorely missing.

I would even go as far as to say raw Future API can be made more concise and more readable than async/await
(and in any case, much closer to the metal)
Compare:
return Future.chain([
   (x) { ...},
   (y) {....},
], firstValue); // firstValue is not really necessary, may come from closure.

With
var v1=await func1(firstValue);
var v2=await func2(v1);
var v3=await func3(v2).
// etc

In the first case, there's less noise (no "async", no "await", no "then"), and the term "chain" clearly says what it's doing.
I think we discussed "chain" at some point here, but it ended in nothing..

Jim Trainor

unread,
Mar 21, 2015, 7:49:51 PM3/21/15
to mi...@dartlang.org
The "firstValue" is/was needed as an argument to the call to the first async operation to avoid unwanted event loop interaction.  My own initial implementation did not use it at first, instead I fed in the initial value via an artificial first operation that simply returned that value.  The problem with that approach was that it interacted with the event loop in a way that caused indexed_db transactions to end prematurely (on some browsers, not all, to make it worse!).  So a quick change to pass the value of the first async call fixed it.

I can add that before these lists of chained async ops I used to write the following:

Future foo() {

  Future first() => the first thing;
  Future second(_) => the second thing;
  Future last(_) => the last thing.

  return first().then(second).then(third).
}

That leading call to "first()" with no argument was always awkward and prone to modification the position of that first call in the chain was modified.  So then I moved to having all methods take an argument (hence all suitable as arguments to Future.then())... which introduced the "where does the initial value come from".

In 95% of my code there is no need for that first value so it doesn't matter.  It is only the odd cases where even loop interaction is a concern where it matters and that only happens with indexed_db code.  Could be done in other ways that avoid "firstValue".  I haven't examined it deeply. I got it going and moved on.

 

Alex Tatumizer

unread,
Mar 21, 2015, 8:37:11 PM3/21/15
to mi...@dartlang.org
Jim, please note that two variants
1) return first().then(second).then(third) and
2) return Future.chain([first, second, third])
are not completely equivalent
In case of Future.chain(..) (which is hypothetical method under discussion) any errors *synchronously* thrown by call to "first" will be fed into returned Future, instead of propagating up the stack (the latter gives rise to 2 paths of error processing: one through onError, another - through try/catch)

Secondly, no question arises as to where first value comes from. It comes from Future.chain implementation. Can be null if firstValue is not explicitly specified. Everything is symmetric, each method accepts one argument.

(*) Problem of catching errors thrown synchronously in first() can be addressed by:
return new Future(first).then(second).then(third).
Constructor of Future can catch exception (please refer to dartdoc). Still, this looks artificial IMO


Thomas Stephenson

unread,
Mar 22, 2015, 12:55:54 AM3/22/15
to mi...@dartlang.org
@Alex: There's a simple implementation of foldAsync function in the quiver package that I use all the time, there's no need for it to be a method on `Future`. Also it's simple enough  to implement yourself if you don't want the dependency.

That said, it _is_ surprising that Future.fold isn't in the futures api. I'd star an issue to add it if you know of one.

And as an unrelated question, why isn't the `stack_trace` behaviour the default way of recording stack traces in async code? Is it a case of adding too much overhead to the calling of futures? Because putting it in a seperate package doesn't reduce the runtime overhead at all -- if I'm debugging some async code and I add a `capture` or `chain` to a piece of code to keep track of errors then I'm certainly not going to remove again it just because I've finished debugging.



Thomas Stephenson

unread,
Mar 22, 2015, 1:04:06 AM3/22/15
to mi...@dartlang.org
ps. I've avoided adding the `stack_trace` dependency for a long time, even after seeing it used in the `pub` code, mainly because (although I knew what it did) there wasn't a good tutorial around to reduce the cognitive overhead of learning the API. 

I basically debug async code by print statement, and I'm sure a lot of other people do too. I think all this clamour about async being a *censored* would be relieved somewhat if some work was put into educating people about how to properly track errors in async code.

Thomas Stephenson

unread,
Mar 22, 2015, 1:21:43 AM3/22/15
to mi...@dartlang.org
pps. Sorry, I just looked it up -- the function is `reduceAsync(Iterable iterable, initialValue, AsyncCombiner combine)` and you get your `Future.chain` function from it as follows:

chain(List<Future> futures, initialValue) =>
   reduceAsync(futures, initialValue, (result, f) => f(result));

But the `reduce` signature is more general anyway.

Alex Tatumizer

unread,
Mar 22, 2015, 8:15:27 AM3/22/15
to mi...@dartlang.org
@Thomas: from utilitarian perspective - yes. From philosophical perspective - no.
Every library aspires to become more than a piece of code. It wants to go into our head and create a set of concepts there. Concepts that make it easier to think about some problem.
"chain" is a handy concept. Library missed a chance to define a useful word, Sure, you can go elsewhere and borrow it (e.g. from quiver) or you can write your own - this is all beside the point. Missed opportunity for Future, that's what it is.
Not the only omission. There's another one: method "wait", which is doing the right thing, but under the wrong name. It's not "wait", it's "parallel", and that's how you would explain what it's doing to somebody understandably confused about its meaning. 

Thomas Stephenson

unread,
Mar 22, 2015, 9:53:54 AM3/22/15
to mi...@dartlang.org
Well as far as adding a `fold` static method, it would be an entirely backwards compatible change so there's no reason not to. I was just saying that there are simple solutions that don't require adding it to the core libraries.

As for your `chain` method
- A `fold` method with a `combine` argument is strictly more general than `chain`, and is familiar to people from other languages; 
- If a fold method was added, chain would be completely unnecessary, just like a `concat` method would be useless on the `Iterable` api; and
- there's already a `Chain` class in the stack_trace library which performs a completely different function -- I think it's used to track which future to follow in the stack trace, but I'm not sure because as stated I don't use the library*; and

`wait` is indeed a misnomer, but that boat has already sailed.

- Thomas

* I want to, because it sounds like a good idea and errors are a bit of a pain point in async. But a tutorial from someone versed in how to correctly do async error handling would be a godsend.

Alex Tatumizer

unread,
Mar 22, 2015, 10:23:42 AM3/22/15
to mi...@dartlang.org
Thomas,
I'm afraid we are talking about completely different things.
"reduce" calls THE SAME function iteratively.
"Chain" is about calling DIFFERENT function in a sequence, passing the result of previous one to the next one.
FirstValue is a parameter passed to first function.
So,
Future.chain([f1, f2, f3], firstValue) is equivalent to

var v1=await f1(firstValue);
var v2=await f2(v1);
var v3=await f3(v2)

NOTE that f1, f2, f3 are all different functions

Thomas Stephenson

unread,
Mar 22, 2015, 10:33:21 AM3/22/15
to mi...@dartlang.org
I'm afraid we're talking about the same thing. I was merely noting the similarity of the `Chain` class to `chain`, not that that matters (although they are both libraries maintained by core developers which (arguably/probably) should be used in a majority of libraries).

I was saying that `fold` would be a better candidate for addition than `chain`, and that:

Future.fold(fs, firstValue, combine: (result, f) => f(result));

would be equivalent to ... (not that fs is an iterable of different functions).

But fold would also be capable of 

Future.fold(files, <int>[], (result, file) async {
  var fileBytes = await file.readBytes();
  return result..addAll(fileBytes);
});

--

Thomas Stephenson

unread,
Mar 22, 2015, 10:44:12 AM3/22/15
to mi...@dartlang.org
correction: _note_ that fs is an iterable of different functions (eg. [f1, f2, f3]).

My meaning is completely lost without that correction :). Fold is strictly more generic than chain (which is just `concat` in a different monad).

Jim Trainor

unread,
Mar 22, 2015, 10:54:08 AM3/22/15
to mi...@dartlang.org
Perhaps create a pub package to collect this useful stuff. Maybe a simple package that isolates simple patterns that make async easier to understand would be helpful.  Offer a "parallel" function that redirects to the core, poorly named, "wait".  Include the "chain" function, etc.  Perhaps manage it a set of operations which are considered candidates for inclusion in the core dart sdk.

"Future.chain" might more aptly be called "Future.serial" if the existing "Future.wait" is renamed "Future.parallel".

I've thought also of representing serial and parallel async operation lists as specialized classes, or combining via some sort of smart builder class, so that I can generically build, and execute, complex operations that combine serial and parallel async sub-operations.  It then makes sense, also, to build custom execution engines, e.g. a debug engine that inserts tracing or breaks points between operations.

--

Thomas Stephenson

unread,
Mar 22, 2015, 10:57:39 AM3/22/15
to mi...@dartlang.org
There already _is_ this sort of package -- it's called `quiver.async`. That was my initial point (which was unfortunately too "utilitarian").

Günter Zöchbauer

unread,
Mar 22, 2015, 11:21:37 AM3/22/15
to mi...@dartlang.org
You can also create your own Future class by extending Future and add methods you miss.

Alex Tatumizer

unread,
Mar 22, 2015, 11:26:49 AM3/22/15
to mi...@dartlang.org
> You can also create your own Future class by extending Future and add methods you miss.
Guys, sorry but it all doesn't address philosophical point I tried to make.
It was a suggestion on how to improve Future library.
And sure, you can always say: "if you don't like this novel, write your own", or "if you don't like this song, write your own".

Jim Trainor

unread,
Mar 22, 2015, 11:58:43 AM3/22/15
to mi...@dartlang.org
I looked at quiver.  Too broad for my taste.  I'd rather have a package with the just the best additions to async separate from the rest of it.



Justin Fagnani

unread,
Mar 22, 2015, 5:11:46 PM3/22/15
to General Dart Discussion

We're going to split Quiver up at some point soon to address this issue. The individual libraries in Quiver are adjust very focused though.

In the mean time Quiver is very actively maintained, has great test coverage, and is used extensively within Google. I'd personally say it's a good choice :)

Justin Fagnani

unread,
Mar 22, 2015, 5:15:19 PM3/22/15
to General Dart Discussion

I just can't agree that this is a problem. The benefit of a great package system, logical core interfaces, and a smart community, is that in most cases you don't need to rely on any one gate keeper to add useful functionality.

Alex Tatumizer

unread,
Mar 22, 2015, 8:00:35 PM3/22/15
to mi...@dartlang.org
Justin: it seems we (you and me) belong to different schools of philosophical thought. That's fine. There are many schools, one can choose, mix and match.

I think that the goal of library is, first and foremost, to introduce a vocabulary to facilitate thinking.  And only as a consequence, help writing code by providing building blocks that correspond to the words of this vocabulary.

Word "chain" (or "serial", if you will, especially if paired with "parallel") is important IMO. And it's not there. Neither in Future, nor in quiver. Sure, you can express it via "reduce", or via then(), or in million other ways. But that's not the point. Following the logic "you can express x via y" I can prove that you don't need cos(x) because it's sin(x+PI/2), you don't need string addition because you can use "$x$y", you don't need x-y because it's the same as x+(-y), and you don't need... basically anything except 3 instructions that define minimal Turing-complete machine.

Again, this is not something that you necessarily have to agree with. Just wanted to be sure I expressed the point clearly.



Jim Trainor

unread,
Mar 22, 2015, 8:26:06 PM3/22/15
to mi...@dartlang.org

+1 for Alex's point below

On Sun, Mar 22, 2015 at 8:00 PM, Alex Tatumizer <tatu...@gmail.com> wrote:
.... snip
 
Word "chain" (or "serial", if you will, especially if paired with "parallel") is important IMO. And it's not there. Neither in Future, nor in quiver. 

... snip 

David Notik

unread,
Mar 23, 2015, 12:15:16 AM3/23/15
to mi...@dartlang.org
Bob's post is exactly the kind of education I was looking for. Very enlightening (and entertaining)! Thank you.
--

Jim Trainor

unread,
Mar 23, 2015, 5:47:30 AM3/23/15
to mi...@dartlang.org
I get that async/await is future based.

That problem was that dart2js wouldn't compile it!

On Saturday, March 21, 2015 at 1:12:17 PM UTC-4, Justin Fagnani wrote:


On Mar 21, 2015 4:33 AM, "Jim Trainor" <jim.train...@gmail.com> wrote:
>
> I tried async/await then backed away when dart2js threw it hands up.  When it's is ready I will try again, although I pretty much am totally used to the future model at this point.

The model is exactly the same though. async/await is based on Futures.

  

Kevin Millikin

unread,
Mar 23, 2015, 5:54:56 AM3/23/15
to mi...@dartlang.org
On Fri, Mar 20, 2015 at 5:40 PM, 'Bob Nystrom' via Dart Misc <mi...@dartlang.org> wrote:

On Fri, Mar 20, 2015 at 1:48 AM, Rat Jo <jora...@gmail.com> wrote:

Since I started to use async/await, my life have become hell. Here is some the few reason why:

dart:core-patch/object_patch.dart 42          Object._noSuchMethod
dart:core-patch/object_patch.dart 45          Object.noSuchMethod
package:async_await/src/xform.dart 854        AsyncTransformer._translateSynchronousForEach
package:async_await/src/xform.dart 892        AsyncTransformer.visitForEachStatement
package:analyzer/src/generated/ast.dart 7003  ForEachStatement.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit

This is a bug in the async_await compiler.

Yeah, that's just a bug in the implementation.  Sorry.

The stack trace seems different from issue 84, though.  It might be issue 83, which was fixed right after it was filed.  If you are still seeing this, please file an issue with more context (hopefully a test case) on the github async_await project, and I'll fix it.

Jim Trainor

unread,
Mar 23, 2015, 7:31:49 AM3/23/15
to mi...@dartlang.org
... lost in the conversation about the fine points of the programming model I only now noticed that the original question pertained directly to indexed_db.

Rat Jo - Also keep in mind that an indexed_db transaction is tied to the event loop.  It is painfully easy to write async code in Dart that inadvertently causes your indexed_db transaction to close if you are not careful. It can be hard to understand what is going on until you understand indexed_db behaviour, the dart async programming model, and how dart interacts with the browser event loop. Further, the exact behaviour will vary between browsers and you'll find that indexed_db code that works fine in Dartium or Chrome fails in some other browser (not a Dart or dart2js problem per-se).  I can tell you that it *will* work if you stick with it. As usual, the best advice is to keep things simple (therefore perhaps avoid async/await until they mature). I have complex index_db Dart code running in Dartium, Chrome (desktop + android), IE, Safari (osx + ios), Opera, and Firefox - every where that I expect Dart+dart2js code to work and where I expect indexed_db to work.

Another complicating factor to be aware of is that indexed db is not fully implemented across all browsers. Generally it is immature except in Chrome. Firefox is next best. If you care about cross browser compatibility be sure to test your code early.


On Friday, March 20, 2015 at 4:48:18 AM UTC-4, Rat Jo wrote:

Since I started to use async/await, my life have become hell. Here is some the few reason why:

dart:core-patch/object_patch.dart 42          Object._noSuchMethod
dart:core-patch/object_patch.dart 45          Object.noSuchMethod
package:async_await/src/xform.dart 854        AsyncTransformer._translateSynchronousForEach
package:async_await/src/xform.dart 892        AsyncTransformer.visitForEachStatement
package:analyzer/src/generated/ast.dart 7003  ForEachStatement.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit
- As soon as you add one await somewhere, your whole program transform in a await/async hell/mess where you have to add them to almost all of your function, because I'm trying to use indexeddb, so every time you want to access your data, it's a "await".
- If you want to use IndexedDb, you don't have much choose then to use async/await.
- Sometime, just marking some function async make the compiler throwing the towel and give crazy number of error. You have to change the error of function, split function, change variable name, etc.. to eventually get your code working...
- You make unittest program to test your website? all of your function start with an await


It's have been since async/await have been available that I started to use them which is now almost three month and those problem didn't go away, not even with the latest 1.9.0-dev.10.10 (rev 44550).

So, I got one suggestion, if you think about starting to use await/async, don't do it.

Bob Nystrom

unread,
Mar 23, 2015, 12:33:15 PM3/23/15
to General Dart Discussion

On Sun, Mar 22, 2015 at 9:15 PM, David Notik <dave...@gmail.com> wrote:
Bob's post is exactly the kind of education I was looking for. Very enlightening (and entertaining)! Thank you.

\o/

- bob

Günter Zöchbauer

unread,
Mar 23, 2015, 1:32:14 PM3/23/15
to mi...@dartlang.org
There are a few bugs in my example. 
If the function catches the error the unittest framework doesn't recognize failed tests.
It seems unittest 0.12.0-alpha.1 uses the stack_trace packages already.

On Saturday, March 21, 2015 at 6:01:31 PM UTC+1, Günter Zöchbauer wrote:
I agree, all these async stack frames are useless noise if you're not actually debugging how futures and zones work which I usually don't do.

You can create a helper to wrap each tests code with Chain capture.

stackTrace(void test()) {
 
Chain.capture(() => test(), onError: (error, stack) {
    _log
.shout(error);
    _log
.info(stack.terse);
 
});
}

void main() {
  initLogging
();

 
group('lib', () {

    test
('basic', () => stackTrace(() {
     
return new Future(() => someFunc());
   
}));
 
});
}

someFunc
() => new Future(()=> someOtherFunc());

someOtherFunc
() => new Future(() => expect(false, isTrue));

but maybe there are better ways.

On Saturday, March 21, 2015 at 5:17:25 PM UTC+1, Jim Trainor wrote:
No I haven't used stack_trace.  I'll likely add it to my top level exception handler for error capture and reporting in the deployed application.  Should be natively supported by the dart debugger.  When I'm debugging an errant exception I am normally in a unit test.  The unit test package implements the top level exception handler and it doesn't report a full stack trace when an expect(...) fails. Maybe that's a place to integrate stack_trace.... or maybe I need to go look at my tests and understand better how it might be employed.


Need it in the debugger but default to be most useful.

On Saturday, March 21, 2015 at 8:01:14 AM UTC-4, Günter Zöchbauer wrote:
Do you use the stack_trace package?
While it's around for a long time I didn't stumble upon it until very recently
- http://stackoverflow.com/questions/29013591/how-to-get-the-full-stack-trace-for-async-execution
Would be great to have this stack trace available in the debugger as well.

Rat Jo

unread,
Mar 24, 2015, 2:30:24 AM3/24/15
to mi...@dartlang.org
The application I'm designing need to work offline. So I have to completely download the database. Before, I was using localstorage, but it has it's limit. More precisely, it can only store a maximum of 5mb of data. I was gzipping my data and storing it inside localstorage, but I was scare that it wil eventually reach the limit. Also, it was using a lot of ram when I was openning my application. IndexedDb doesn't have to 5mb limit it doesn't load it's database inside the ram.

Problem start with IndexedDb being async. There is a standard for sync, but no browser to this date implement any of it.

Future is great, but it's not always possible to use it in an efficient way. The project I'm working on, use a lot of computation and they go like this (this is not the actual code as I'm not authorized to post it here, but something similar that use the same structure, but on a much bigger scale) :

var surface = length_odd_wall * length_even_wall;
var volume = surface * height;
var nbre_equip1 = surface / 4;
var nbre_equip2 = surface / 2;
var nbre_equip3 = surface * 4;
var nbre_equip4 = volume;
var nbre_equip5 = 7;
var nbre_equip6 = (await equip_type_index.getByIndex('variable_name', 'equip6'))['default_qty'];


var cost_equip1 = nbre_equip1 * (await equip_type_index.getByIndex('variable_name', 'equip1'))['selling'];
var cost_equip2 = nbre_equip2 * (await equip_type_index.getByIndex('variable_name', 'equip2'))['selling'];
var cost_equip1_2 = (cost_equip1 + cost_equip2) * (await configuration_index.getByIndex('variable_name', 'factor1'))['value'];


var cost_equip3 = nbre_equip3 * (await equip_type_index.getByIndex('variable_name', 'equip3'))['selling'];
var cost_equip4 = nbre_equip4 * (await equip_type_index.getByIndex('variable_name', 'equip4'))['selling'];
var cost_equip5 = nbre_equip5 * (await equip_type_index.getByIndex('variable_name', 'equip5'))['selling'];
var cost_equip6 = nbre_equip6 * (await equip_type_index.getByIndex('variable_name', 'equip6'))['selling'];
var cost_equip3_4_5_6 = (cost_equip3 + cost_equip4 + cost_equip5 + cost_equip6) * (await configuration_index.getByIndex('variable_name', 'factor2'))['value'];


var sub_total_cost = cost_equip1_2 * cost_equip3_4_5_6;
var tax1 = sub_total_cost * (await configuration_index.getByIndex('variable_name', 'tax1'))['value'];
var tax2 = sub_total_cost * (await configuration_index.getByIndex('variable_name', 'tax2'))['value'];
var total_cost = sub_total_cost + tax1 + tax2;


For reference, getByIndex is defined as fallow:

Map getByIndex(String index, dynamic value) async {
   
var transaction = _db.transaction(storageName, 'readonly');
   
var objectStore = transaction.objectStore(storageName);
   
return await objectStore.index('${index}_index').get([value, 1]);
 
}

I use await instead of returning a future here because I can't change the signature of the function. Also, in the first code, I'm supposed to eventually allow people to change formula. At first I though that I will call eval from js, but all those await are throwing me off... Anyway, that's an another story.

So, by having code like that, it break the code at multiple place and pause the execution causing delay and problem with the data. I now lock my database, but before I added a lock, I could receive data from the network which will update the data and cause weird behavior in my computation.

Now, the other thing. "Having a super async interface". I know how to do it. The problem is that you can't know when it's gonna be finish. Well, I just thought that I could probably save all future in an array and wait for them... The thing is it's easy to display something on the screen in an async way, but I'm also generating html code that I send to a server to create a pdf using wkhtmltopdf. So I need to be able to know at when it's done.

Kevin Millikin, the error that I put there is only part of it and it's a 200+ lines error. It's indeed not the same error as of issue 84 on github. It happened when a decided to transform a function by only adding "async" keyword to it. Nothing else. No await, no additionnal code, nothing. Just the keyword, but I could not isolate the error in simple program.

  void _socketIoEmit_Callback(js.JsObject js_socket, js.JsObject b) async {
   
.
   
.
   
.
 
}

 
Quote from Bob: This is a bug in the async_await compiler. Note that this is unrelated to the native implementations of async/await in the VM and dart2js. That compiler exists mainly as a temporary way to let us experiment with using async/await in Dart code before any native implementations of it existed.
If you're on the latest dev builds of the SDK, I encourage you to stop using the async_await compiler and just use the VM's and dart2js's native implementations of it. I'm not promising that they're bug-free either, but they are getting a lot more love and attention than the compiler is.

Bob, I use Dart for two reason: It compile to javascript and it help me code faster because of the job the editor is doing such as code completion. I have no interest in using the VM at this time, nor does my client. Also, Dart VM still does not support Js on the server side. You would kick the VM out and I would still be an happy man. The VM is great for test and debugging. but it's totally useless for me if it doesn't compile to Js. You will probably tell me that it's not finish... but it look pretty finish to me...

Quote from Jim Trainor: ... I know also that I've had to tweak mine over time to property deal with indexed_db interactions (indexed_db closes the transaction when you leave the event loop without an db operation outstanding. It's easy to do by accident so one must be careful. Further the behaviour varies between browsers so it's nice stay in control...).

Jim, thanks for your comment, as of right now, IndexedDb does not give me any problem in itself. It's just the async nature of it that force me to make all my code async and it's messing with everything. I never close them, but I always open a new objectStore when I need them, since that moment, I never had problem with it anymore and I have a lot of data and table.

Günter Zöchbauer, my unittest is using a custom test function as the default test function that was coming with the unittest package whould not support await in a way that was good for me. It call the test function without executing it. So, if you do stuff before or after the test function, it mess your logic. I mint have to still take a look at how you did them inside Dart...

My real point is that there shouldn't be any async keyword and all the await done automatically. This way, I would not need to write two function everytime there is a possibility that I need both. I think the new generator keyword yield in ES6 will solve a lot of those problem. And I think it actually make it in a way that you don't need to add anything to other function that is calling the function that contain a yield which should be the default behavior.

Günter Zöchbauer

unread,
Mar 24, 2015, 3:44:39 AM3/24/15
to mi...@dartlang.org
It doesn't work this way. By adding `async` you change the return type to Future if it isn't already.
The signature of the function above is invalid.
 
Also, in the first code, I'm supposed to eventually allow people to change formula. At first I though that I will call eval from js, but all those await are throwing me off... Anyway, that's an another story.

So, by having code like that, it break the code at multiple place and pause the execution causing delay and problem with the data. I now lock my database, but before I added a lock, I could receive data from the network which will update the data and cause weird behavior in my computation.

Now, the other thing. "Having a super async interface". I know how to do it. The problem is that you can't know when it's gonna be finish. Well, I just thought that I could probably save all future in an array and wait for them... The thing is it's easy to display something on the screen in an async way, but I'm also generating html code that I send to a server to create a pdf using wkhtmltopdf. So I need to be able to know at when it's done.

Kevin Millikin, the error that I put there is only part of it and it's a 200+ lines error. It's indeed not the same error as of issue 84 on github. It happened when a decided to transform a function by only adding "async" keyword to it. Nothing else. No await, no additionnal code, nothing. Just the keyword, but I could not isolate the error in simple program.

  void _socketIoEmit_Callback(js.JsObject js_socket, js.JsObject b) async {
   
.
   
.
   
.
 
}


Same here, you can't have a function with `async` and a return type void. The return type is `Future`.
 
 
Quote from Bob: This is a bug in the async_await compiler. Note that this is unrelated to the native implementations of async/await in the VM and dart2js. That compiler exists mainly as a temporary way to let us experiment with using async/await in Dart code before any native implementations of it existed.
If you're on the latest dev builds of the SDK, I encourage you to stop using the async_await compiler and just use the VM's and dart2js's native implementations of it. I'm not promising that they're bug-free either, but they are getting a lot more love and attention than the compiler is.

Bob, I use Dart for two reason: It compile to javascript and it help me code faster because of the job the editor is doing such as code completion. I have no interest in using the VM at this time, nor does my client. Also, Dart VM still does not support Js on the server side. You would kick the VM out and I would still be an happy man. The VM is great for test and debugging. but it's totally useless for me if it doesn't compile to Js. You will probably tell me that it's not finish... but it look pretty finish to me...


Dart2js has async/await integrated as well. No need for the transformer AFAIK
 
Quote from Jim Trainor: ... I know also that I've had to tweak mine over time to property deal with indexed_db interactions (indexed_db closes the transaction when you leave the event loop without an db operation outstanding. It's easy to do by accident so one must be careful. Further the behaviour varies between browsers so it's nice stay in control...).

Jim, thanks for your comment, as of right now, IndexedDb does not give me any problem in itself. It's just the async nature of it that force me to make all my code async and it's messing with everything. I never close them, but I always open a new objectStore when I need them, since that moment, I never had problem with it anymore and I have a lot of data and table.

Günter Zöchbauer, my unittest is using a custom test function as the default test function that was coming with the unittest package whould not support await in a way that was good for me. It call the test function without executing it. So, if you do stuff before or after the test function, it mess your logic. I mint have to still take a look at how you did them inside Dart...


Sounds weird. Could be worth to provide more information to find the cause of the problem. 
 
My real point is that there shouldn't be any async keyword and all the await done automatically. This way, I would not need to write two function everytime there is a possibility that I need both. I think the new generator keyword yield in ES6 will solve a lot of those problem. And I think it actually make it in a way that you don't need to add anything to other function that is calling the function that contain a yield which should be the default behavior.

It seems you try to avoid async execution. This just doesn't work in Dart. I think the better way is to provide only an async API instead of both and if you don't have any async operation in one implementation just return `new Future.value(x);`

Kevin Millikin

unread,
Mar 24, 2015, 4:08:54 AM3/24/15
to mi...@dartlang.org
On Tue, Mar 24, 2015 at 7:30 AM, Rat Jo <jora...@gmail.com> wrote:

Kevin Millikin, the error that I put there is only part of it and it's a 200+ lines error. It's indeed not the same error as of issue 84 on github. It happened when a decided to transform a function by only adding "async" keyword to it. Nothing else. No await, no additionnal code, nothing. Just the keyword, but I could not isolate the error in simple program.

  void _socketIoEmit_Callback(js.JsObject js_socket, js.JsObject b) async {
   
.
   
.
   
.
 
}

 
As a user you certainly have a right to complain about buggy code.  However, if you want it to be less buggy you'll have to tell us about the bugs you find.

I think what you're describing is https://github.com/dart-lang/async_await/issues/83, but please do let me know if the issue recurs even after that patch.  If you can't provide a test case, a stack trace is helpful.

As Günter points out, writing async around a function body will require you to change the signature unless it already returned Future, in exactly the same way as if you wrapped the body B in 'return new Future(() { B })'.

As far as avoiding so many awaits, you might consider structuring your code more like this (untested):

var surface = length_odd_wall * length_even_wall;
var volume = surface * height;
var nbre_equip1 = surface / 4;
var nbre_equip2 = surface / 2;
var nbre_equip3 = surface * 4;
var nbre_equip4 = volume;
var nbre_equip5 = 7;

var equipmentKeys = [
  'equip6', 'equip1', 'equip2', 'equip3', 'equip4', 'equip5', 'equip6', 'tax1',
  'tax2',
];
var equipmentValues = await Future.wait(keys.map(
    (k) => equip_type_index.getByIndex('variable_name', k)));
var equipment = new Map.fromIterables(equipKeys, equipValues);

var configurationKeys = [
  'factor1', 'factor2', 'tax1', 'tax2',
];
var configurationValues = await Future.wait(keys.map(
    (k) => configuration_index.getByIndex('variable_name', k)));
var configuration =
  new Map.fromIterables(configurationKeys, configurationValues);
  
var nbre_equip6 = equipment['equip6']['default_qty'];
var cost_equip1 = nbre_equip1 * equipment['equip1']['selling'];
var cost_equip2 = nbre_equip2 * equipment['equip2']['selling'];
var cost_equip1_2 =
  (cost_equip1 + cost_equip2) * configuration['factor1']['value'];

var cost_equip3 = nbre_equip3 * equipment['equip3']['selling'];
var cost_equip4 = nbre_equip4 * equipment['equip4']['selling'];
var cost_equip5 = nbre_equip5 * equipment['equip5']['selling'];
var cost_equip6 = nbre_equip6 * equipment['equip6']['selling'];
var cost_equip3_4_5_6 = (cost_equip3 + cost_equip4 + cost_equip5 + cost_equip6)
  * configuration['factor2']['value'];

var sub_total_cost = cost_equip1_2 * cost_equip3_4_5_6;
var tax1 = sub_total_cost * configuration['tax1']['value'];
var tax2 = sub_total_cost * configuration['tax2']['value'];

Grant Jason

unread,
Mar 24, 2015, 4:41:26 AM3/24/15
to mi...@dartlang.org
+1000 for Alex

I hope this doesn't just get ignored, and we continue to have naming that forces us to memorize, due to lack of correlation.

Jim Trainor

unread,
Mar 24, 2015, 5:51:12 AM3/24/15
to mi...@dartlang.org

A couple of additional about indexed_db issues worth noting:

1) Completer.sync: The only circumstance where I *had* to use Completer.sync() was with indexed_db.  Use it in cases where you've wrapped the db call, which itself returns a future whose completion you need to propagate using your own future (provided by Completer.sync().  If you use a regular Completer you will *leave the event loop* and the transaction will close before you start the next operation.  Without experimenting I'm not sure how to express that using async/await.

2) Multiple cursors:  This is another case where I accidentally left the event loop and encountered errors and the behaviour was browser dependant.  Initially I serialized my cursors. i.e. run the first to completion, then the second, then the third. That was fine in chrome, didn't work in others.  The solution was to start all cursors at the same time and then perform a parallel wait (i.e. Future.wait()).

3) Browser capabilities: Here are the things you need to be concerned about insofar as cross browser support is considered: i) multi-store transactions, ii) array as key, iii) dot notation key access, iv) compound index keys, v) in-cursor delete, v) clean exception propagation (some indexed_db exceptions escape the dart zone error handler, on firefox I recall - need file a bug on that).  This demonstrates most of the limitations, not all: http://codepen.io/cemerick/pen/Itymi

If you depend on any of those then you need to find work-arounds. Safari's brand new indexed_db implementation is incredibly slow.  Doesn't work at all in iOS webkit yet.  I have wrapped my indexed_db code in a private interface as an escape hatch in case I need(ed) to provide an alternate solutions. It's not looking like alternates will be necessary as long as webkit gets indexed_db support in the near future.  If not then plan b is to implement my private interface using web-sql which is available in webkit.

Personally, there is enough going on here that I wouldn't want to add the additional complication of async/await keywords without nearly perfect knowledge of how those are translated into futures and completions.

Jim Trainor

unread,
Mar 24, 2015, 6:33:45 AM3/24/15
to mi...@dartlang.org
My own code would break this into distinct phases: i) start the transaction, ii) one function per db call to fetch data, iii) complete the result, iv) clearly synchronize the macro operation with the transaction close (transaction.future).

It does end up organized into a number of small functions but those are typically one line inner functions in my code.  I don't find this disagreeable but then again I've been doing it that way from the start so I'm used to it. In fact I find the inline "await" calls harder to grock.

A synchronous indexed_db interface will likely never appear.  I'm not sure it would add anything if it did exist.  It could only used outside the browsers event loop and then you'd end up having async code in the main loop waiting on the synchronous db code running in the thread - so the problem has simply been shifted. 

I actually find all this async stuff in the browser refreshing. One of my early programming jobs involved X servers (i.e. the display server). It was very normal to serve many tens of busy clients sending very fine grain drawing commands - all from a single thread running off a select call.  Then programming went down the path of over-use of threads often simply so that programmers could use simple synchronous IO interfaces (thanks for that java - many respected universities taught their students that garbage only for them to have to unlearn it later), and then people discovered it didn't scale (surprise!). Then we all returned to async io to restore performance.  Now we are revisiting hybrid solutions that fold in language support to keep things async and light but provide the illusion of synchronous interaction.  While that is all going on, however, one could simply just bite the bullet, write async code, and get on with one's life.

Jim Trainor

unread,
Mar 24, 2015, 8:22:11 AM3/24/15
to mi...@dartlang.org
> So, by having code like that, it break the code at multiple place and pause the execution causing delay and problem with the data. I now lock my database, but before I
> added a lock, I could receive data from the network which will update the data and cause weird behavior in my computation.

.... the transaction should be your "lock".  You're too fine grained in your transaction at the moment.  Move it out of getByIndex() and put it higher up the execution at a point that will encompass the set of operations that need to be locked.  Performance will likely improve also.

Bob Nystrom

unread,
Mar 24, 2015, 12:43:06 PM3/24/15
to General Dart Discussion

On Tue, Mar 24, 2015 at 12:44 AM, Günter Zöchbauer <gzo...@gmail.com> wrote:
Quote from Bob: This is a bug in the async_await compiler. Note that this is unrelated to the native implementations of async/await in the VM and dart2js. That compiler exists mainly as a temporary way to let us experiment with using async/await in Dart code before any native implementations of it existed.
If you're on the latest dev builds of the SDK, I encourage you to stop using the async_await compiler and just use the VM's and dart2js's native implementations of it. I'm not promising that they're bug-free either, but they are getting a lot more love and attention than the compiler is.

Bob, I use Dart for two reason: It compile to javascript and it help me code faster because of the job the editor is doing such as code completion. I have no interest in using the VM at this time, nor does my client. Also, Dart VM still does not support Js on the server side. You would kick the VM out and I would still be an happy man. The VM is great for test and debugging. but it's totally useless for me if it doesn't compile to Js. You will probably tell me that it's not finish... but it look pretty finish to me...


Dart2js has async/await integrated as well. No need for the transformer AFAIK

That's correct. My emphasis added above.

- bob

Justin Fagnani

unread,
Mar 24, 2015, 1:28:43 PM3/24/15
to General Dart Discussion
On Tue, Mar 24, 2015 at 1:41 AM, Grant Jason <grant...@gmail.com> wrote:
+1000 for Alex

I hope this doesn't just get ignored, and we continue to have naming that forces us to memorize, due to lack of correlation.

This is a good time to point out that Future.parallel() is probably _not_ a better name for Future.wait() :) 

All Future.wait() does is... wait for a set of Futures to complete.

It does not create the Futures, or the code that created them, and implies no ordering or concurrency that code. The actual execution of the code controlling the Futures may be parallel, or serial, or it may be one block of code controlling multiple Futures, or nay combination thereof.

To make this clear we can create an example of a set of non-parallel tasks that are waited for with Future.wait(). Imagine some Task class that can be started at some point in the future. You can listen to when the task starts and finishes via Futures, and the finished Future is accessible even before the Task starts. You can Future.wait() for all tasks to finish, but only execute the tasks one at a time.

class Task {
  /// completes when the task is started
  Future get started;

  /// completes when the task is finished
  Future get finished;

  /// starts the task
  execute();
}

// given a collection of tasks
var tasks;

// we can wait for all tasks to finish
Future.wait(tasks.map((e) => e.finished)).then((_) => print("done"));

// we can also listen for individual tasks starting and stopping
quiver.enumerate(tasks).forEach((e) {
  var task = e.value;
  var i = e.index;
  task.started.then((_) => print("started task $i"));
  task.finished.then((_) => print("finished task $i"));
});

// and execute them one at a time - no parallelism!
Future.forEach(tasks, (t) => t.execute());

And on the console:
started task 0
finished task 0
started task 1
finished task 1
...
done





On Monday, March 23, 2015 at 2:00:35 AM UTC+2, Alex Tatumizer wrote:
Justin: it seems we (you and me) belong to different schools of philosophical thought. That's fine. There are many schools, one can choose, mix and match.

I think that the goal of library is, first and foremost, to introduce a vocabulary to facilitate thinking.  And only as a consequence, help writing code by providing building blocks that correspond to the words of this vocabulary.

Word "chain" (or "serial", if you will, especially if paired with "parallel") is important IMO. And it's not there. Neither in Future, nor in quiver. Sure, you can express it via "reduce", or via then(), or in million other ways. But that's not the point. Following the logic "you can express x via y" I can prove that you don't need cos(x) because it's sin(x+PI/2), you don't need string addition because you can use "$x$y", you don't need x-y because it's the same as x+(-y), and you don't need... basically anything except 3 instructions that define minimal Turing-complete machine.

Again, this is not something that you necessarily have to agree with. Just wanted to be sure I expressed the point clearly.

--

Alex Tatumizer

unread,
Mar 24, 2015, 1:42:19 PM3/24/15
to mi...@dartlang.org
Sure, then it's easy to add "parallel". It should be a generalization of new Future(computation)., where computation is a FUNCTION that returns a future. So, new Future.parallel will accept an Iterable of "computations".

And then, everything becomes truly symmetric: we can introduce new Future.chain(), also with list of "computations", just called one after the other.
How about that?

Alex Tatumizer

unread,
Mar 24, 2015, 1:44:02 PM3/24/15
to mi...@dartlang.org
Typo: not "chain", but "serial", sorry

Justin Fagnani

unread,
Mar 24, 2015, 3:22:32 PM3/24/15
to General Dart Discussion
At that point, parallel() becomes this:

Future.wait(computations.map((c) => c())

And chain() is still:
reduceAsync(computations, initial, (prev, c) => c(prev))

But... there are variations. We added forEachAsync to Quiver because we had users who wanted to control the number of outstanding tasks. With parallel(), people might want to specify arguments to the functions. With chain() you might want to transform the intermediate results in some way, or use functions that take two arguments, etc.

Creating more higher level operations and possibly their variants has a cost in terms of the sheer size of a API that users must learn. At some point the best thing for the core library is to offer simple primitives that can be composed in familiar patterns, and let users and libraries build convenience functions that are shorthand for certain patterns. chain() is not a primitive because it's a special case of reduce(), and so easily expressed in terms of reduce().

To judge the utility of chain() for async, I'd look to symmetry: is the analog sync version important enough to be in core?

// calls each function with the result of the previous
chain(initialValue, Iterable<Function> functions);

And I personally would conclude no: chain() is just: functions.fold(initialValue, (prev, f) => f(prev))

Now maybe chain() could go in a package, but the bar is higher for core libs.

I agree with you that libraries should encourage ways of thinking, and this is why the functional collection primitives like map(), where(), fold(), etc., are so important. They can be combined in all kinds of powerful ways, and users really should get familiar with them. Then it's the core libraries responsibility to make sure that that knowledge can be applied to collections, streams, with either sync or async callback functions. This symmetry is what's really important, so that you don't have to learn entirely new operations.

This approach gives users the choice of understanding a smaller set of primitives and how to combine them in useful ways, or learning a larger set of higher-level functions.

I'd also point out that the use case for chain() in the context of this thread is a little dubious to me. Instead of a collection of arbitrary Future-producing functions, the example was a set of known functions, structured in a known way. chain() would probably be better replaced by:

var r1 = await f1();
var r2 = await f2(r1);

In the same way that you'd do with synchronous functions:

var r1 = f1();
var r2 = f2(r1);

As a code reader, I'd rather see this than something like chain(null, [f1, f2]) because it's more plain and explicit.



On Tue, Mar 24, 2015 at 10:43 AM, Alex Tatumizer <tatu...@gmail.com> wrote:
Typo: not "chain", but "serial", sorry

--

Alex Tatumizer

unread,
Mar 24, 2015, 3:45:45 PM3/24/15
to mi...@dartlang.org
> As a code reader, I'd rather see this than something like chain(null, [f1, f2]) because it's more plain and explicit.
Again, 2 different schools of thought :-)

I confess that the very thought of compiler making forshmak out of my code whenever I write "await" makes me sick.
When you write

var r1 = f1();
var r2 = f2(r1);
- that's exactly what you get.
with await, it's not what you get. You get something completely different.

"await" goes very much beyond normal syntax sugar. It's quite complicated transformation of code.
I know counter-arguments, of course. Still, I'd prefer to keep closer to the metal, especially if library provided more convenient primitives. Both ways are evil, but what is the lesser evil? it is not quite obvious.



Justin Fagnani

unread,
Mar 24, 2015, 3:50:30 PM3/24/15
to General Dart Discussion
On Tue, Mar 24, 2015 at 12:45 PM, Alex Tatumizer <tatu...@gmail.com> wrote:
> As a code reader, I'd rather see this than something like chain(null, [f1, f2]) because it's more plain and explicit.
Again, 2 different schools of thought :-)

I confess that the very thought of compiler making forshmak out of my code whenever I write "await" makes me sick.
When you write
var r1 = f1();
var r2 = f2(r1);
- that's exactly what you get.
with await, it's not what you get. You get something completely different.

That's only true in dart2js. In the Dart VM there's no transformation.

"await" goes very much beyond normal syntax sugar. It's quite complicated transformation of code.
I know counter-arguments, of course. Still, I'd prefer to keep closer to the metal

Then there's this:

f1().then(f2);

But await/async let's you use normal control flow constructs...

, especially if library provided more convenient primitives. Both ways are evil, but what is the lesser evil? it is not quite obvious.



Cristian Garcia

unread,
Mar 24, 2015, 5:35:41 PM3/24/15
to mi...@dartlang.org
I recently saw a video about why Linked-in is using Node.js and Playframework (Scala), and one of the main reasons was because async programming given these facts:

  1. A part of the a code that does IO takes several orders of magnitude more than a "normal" line of code
  2. Therefore, if you use threads, during a requests a thread will spend most of its time just waiting
  3. I you run out of threads, requests start to queue up in your service, and services that depend on it will also start to queue up
Async programming doesn't have this problem since every time it hits a waiting spot it just pauses and continues with the next on that is active, according to the points above, in a busy system, it will probably start attending a new request since the other will probably still be waiting.
Futures might be nicer that callbacks but certainly aren't as nice as blocking (code-wise), however, async/await is the nicest you can get, it REALLY feels like normal code. Just don't use async/await in the browser, I had a bunch of problems with the dart2js transformer, better wait till its officially supported.

Lasse R.H. Nielsen

unread,
Mar 24, 2015, 6:24:01 PM3/24/15
to mi...@dartlang.org


On Mar 24, 2015 10:35 PM, "Cristian Garcia" <cgarc...@gmail.com> wrote:
> Just don't use async/await in the browser, I had a bunch of problems with the dart2js transformer, better wait till its officially supported.

It is officially supported in v1.9, without a transformer.

/L

Cristian Garcia

unread,
Mar 24, 2015, 6:32:05 PM3/24/15
to mi...@dartlang.org
Lasse,

Great! Finally going to clean up my client code :)

When is 1.9 coming out?

Alex Tatumizer

unread,
Mar 24, 2015, 6:47:42 PM3/24/15
to mi...@dartlang.org
> To judge the utility of chain() for async, I'd look to symmetry: is the analog sync version important enough to be in core?
From viewpoint of the school I'm advocating here, it's *very* important for the *words* "chain" (or "serial") and "parallel" to be there in the core. It's not an argument about functionality at all. It's all about words.

But eventually, it's a judgement call. Different things are important for different people. My judgement is no better than anybody else's, so we can just agree to disagree :)


Rat Jo

unread,
Mar 24, 2015, 8:23:34 PM3/24/15
to mi...@dartlang.org
Hmmm, it was indeed something similar to issue 83, I did run into that issue before, but I though it was fixed (Still doing it as of 1.9.0-dev.10.13 (rev 44630)). But it did look different. Before when I was running in that issue, I was actually having an await inside a for loop. This time, I didn't... Just adding async keyword was triggering the bug.

NoSuchMethodError: method not found: 'lexeme'
Receiver: null
Arguments: []

dart
:core-patch/object_patch.dart 42          Object._noSuchMethod
dart
:core-patch/object_patch.dart 45          Object.noSuchMethod
package:async_await/src/xform.dart 854        AsyncTransformer._translateSynchronousForEach
package:async_await/src/xform.dart 892        AsyncTransformer.visitForEachStatement
package:analyzer/src/generated/ast.dart 7003  ForEachStatement.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1530       AsyncTransformer.visitVariableDeclarationStatement.<fn>.<fn>
package:async_await/src/xform.dart 1496       AsyncTransformer._translateDeclarationList.<fn>
package:async_await/src/xform.dart 1487       AsyncTransformer._translateDeclarationList.translateDecl.<fn>
package:async_await/src/xform.dart 1936       AsyncTransformer.visitBooleanLiteral.<fn>
package:async_await/src/xform.dart 1486       AsyncTransformer._translateDeclarationList.translateDecl
package:async_await/src/xform.dart 1511       AsyncTransformer._translateDeclarationList
package:async_await/src/xform.dart 1527       AsyncTransformer.visitVariableDeclarationStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 692        AsyncTransformer._translateStatementList
package:async_await/src/xform.dart 696        AsyncTransformer.visitBlock.<fn>
package:async_await/src/xform.dart 1161       AsyncTransformer.visitIfStatement.<fn>.<fn>
package:async_await/src/xform.dart 1788       AsyncTransformer.visitBinaryExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1798       AsyncTransformer.visitBinaryExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1797       AsyncTransformer.visitBinaryExpression.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1793       AsyncTransformer.visitBinaryExpression.<fn>
package:async_await/src/xform.dart 1787       AsyncTransformer.visitBinaryExpression.<fn>.<fn>
package:async_await/src/xform.dart 1798       AsyncTransformer.visitBinaryExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1944       AsyncTransformer.visitIntegerLiteral.<fn>
package:async_await/src/xform.dart 1797       AsyncTransformer.visitBinaryExpression.<fn>.<fn>
package:async_await/src/xform.dart 2077       AsyncTransformer.visitPropertyAccess.<fn>.<fn>
package:async_await/src/xform.dart 1876       AsyncTransformer.visitPrefixedIdentifier.<fn>
package:async_await/src/xform.dart 2076       AsyncTransformer.visitPropertyAccess.<fn>
package:async_await/src/xform.dart 1793       AsyncTransformer.visitBinaryExpression.<fn>
package:async_await/src/xform.dart 1786       AsyncTransformer.visitBinaryExpression.<fn>
package:async_await/src/xform.dart 1151       AsyncTransformer.visitIfStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1556       AsyncTransformer.visitWhileStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1530       AsyncTransformer.visitVariableDeclarationStatement.<fn>.<fn>
package:async_await/src/xform.dart 1496       AsyncTransformer._translateDeclarationList.<fn>
package:async_await/src/xform.dart 1487       AsyncTransformer._translateDeclarationList.translateDecl.<fn>
package:async_await/src/xform.dart 2077       AsyncTransformer.visitPropertyAccess.<fn>.<fn>
package:async_await/src/xform.dart 2077       AsyncTransformer.visitPropertyAccess.<fn>.<fn>
package:async_await/src/xform.dart 1876       AsyncTransformer.visitPrefixedIdentifier.<fn>
package:async_await/src/xform.dart 2076       AsyncTransformer.visitPropertyAccess.<fn>
package:async_await/src/xform.dart 2076       AsyncTransformer.visitPropertyAccess.<fn>
package:async_await/src/xform.dart 1486       AsyncTransformer._translateDeclarationList.translateDecl
package:async_await/src/xform.dart 1511       AsyncTransformer._translateDeclarationList
package:async_await/src/xform.dart 1527       AsyncTransformer.visitVariableDeclarationStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 692        AsyncTransformer._translateStatementList
package:async_await/src/xform.dart 696        AsyncTransformer.visitBlock.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 829        AsyncTransformer.visitExpressionStatement.<fn>.<fn>
package:async_await/src/xform.dart 2040       AsyncTransformer.visitMethodInvocation.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1898       AsyncTransformer._translateExpressionList.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1917       AsyncTransformer._translateExpressionList
package:async_await/src/xform.dart 2038       AsyncTransformer.visitMethodInvocation.<fn>.<fn>
package:async_await/src/xform.dart 1885       AsyncTransformer.visitIndexExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1884       AsyncTransformer.visitIndexExpression.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1880       AsyncTransformer.visitIndexExpression.<fn>
package:async_await/src/xform.dart 2034       AsyncTransformer.visitMethodInvocation.<fn>
package:async_await/src/xform.dart 827        AsyncTransformer.visitExpressionStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1062       AsyncTransformer.visitForStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1530       AsyncTransformer.visitVariableDeclarationStatement.<fn>.<fn>
package:async_await/src/xform.dart 1496       AsyncTransformer._translateDeclarationList.<fn>
package:async_await/src/xform.dart 1487       AsyncTransformer._translateDeclarationList.translateDecl.<fn>
package:async_await/src/xform.dart 1885       AsyncTransformer.visitIndexExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1975       AsyncTransformer.visitSimpleStringLiteral.<fn>
package:async_await/src/xform.dart 1884       AsyncTransformer.visitIndexExpression.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1880       AsyncTransformer.visitIndexExpression.<fn>
package:async_await/src/xform.dart 1486       AsyncTransformer._translateDeclarationList.translateDecl
package:async_await/src/xform.dart 1511       AsyncTransformer._translateDeclarationList
package:async_await/src/xform.dart 1527       AsyncTransformer.visitVariableDeclarationStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 829        AsyncTransformer.visitExpressionStatement.<fn>.<fn>
package:async_await/src/xform.dart 2046       AsyncTransformer.visitMethodInvocation.<fn>.<fn>
package:async_await/src/xform.dart 1898       AsyncTransformer._translateExpressionList.<fn>
package:async_await/src/xform.dart 1999       AsyncTransformer.visitStringInterpolation.<fn>.<fn>
package:async_await/src/xform.dart 1898       AsyncTransformer._translateExpressionList.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1917       AsyncTransformer._translateExpressionList
package:async_await/src/xform.dart 1987       AsyncTransformer.visitStringInterpolation.<fn>
package:async_await/src/xform.dart 1917       AsyncTransformer._translateExpressionList
package:async_await/src/xform.dart 2045       AsyncTransformer.visitMethodInvocation.<fn>
package:async_await/src/xform.dart 827        AsyncTransformer.visitExpressionStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1530       AsyncTransformer.visitVariableDeclarationStatement.<fn>.<fn>
package:async_await/src/xform.dart 1496       AsyncTransformer._translateDeclarationList.<fn>
package:async_await/src/xform.dart 1487       AsyncTransformer._translateDeclarationList.translateDecl.<fn>
package:async_await/src/xform.dart 1885       AsyncTransformer.visitIndexExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1975       AsyncTransformer.visitSimpleStringLiteral.<fn>
package:async_await/src/xform.dart 1884       AsyncTransformer.visitIndexExpression.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1880       AsyncTransformer.visitIndexExpression.<fn>
package:async_await/src/xform.dart 1486       AsyncTransformer._translateDeclarationList.translateDecl
package:async_await/src/xform.dart 1511       AsyncTransformer._translateDeclarationList
package:async_await/src/xform.dart 1527       AsyncTransformer.visitVariableDeclarationStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 692        AsyncTransformer._translateStatementList
package:async_await/src/xform.dart 696        AsyncTransformer.visitBlock.<fn>
package:async_await/src/xform.dart 636        AsyncTransformer.visitBlockFunctionBody
package:analyzer/src/generated/ast.dart 2902  BlockFunctionBody.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit
package:async_await/src/compiler.dart 45      compile
package:async_await/async_await.dart 10       compile
package:async_await/transformer.dart 25       AsyncAwaitTransformer.apply.<fn>
dart
:async/zone.dart 1155                     _RootZone.runUnary
dart
:async/future_impl.dart 484               _Future._propagateToListeners.handleValueCallback
dart
:async/future_impl.dart 567               _Future._propagateToListeners
dart
:async/future_impl.dart 358               _Future._completeWithValue
dart
:async/future_impl.dart 412               _Future._asyncComplete.<fn>
dart
:async/schedule_microtask.dart 41         _asyncRunCallbackLoop
dart
:async/schedule_microtask.dart 48         _asyncRunCallback
dart
:isolate-patch/isolate_patch.dart 96      _runPendingImmediateCallback
dart
:isolate-patch/isolate_patch.dart 143     _RawReceivePortImpl._handleMessage


dart
:core                                     Object.noSuchMethod
package:async_await/src/xform.dart 854        AsyncTransformer._translateSynchronousForEach
package:async_await/src/xform.dart 892        AsyncTransformer.visitForEachStatement
package:analyzer/src/generated/ast.dart 7003  ForEachStatement.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1530       AsyncTransformer.visitVariableDeclarationStatement.<fn>.<fn>
package:async_await/src/xform.dart 1496       AsyncTransformer._translateDeclarationList.<fn>
package:async_await/src/xform.dart 1487       AsyncTransformer._translateDeclarationList.translateDecl.<fn>
package:async_await/src/xform.dart 1936       AsyncTransformer.visitBooleanLiteral.<fn>
package:async_await/src/xform.dart 1486       AsyncTransformer._translateDeclarationList.translateDecl
package:async_await/src/xform.dart 1511       AsyncTransformer._translateDeclarationList
package:async_await/src/xform.dart 1527       AsyncTransformer.visitVariableDeclarationStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 692        AsyncTransformer._translateStatementList
package:async_await/src/xform.dart 696        AsyncTransformer.visitBlock.<fn>
package:async_await/src/xform.dart 1161       AsyncTransformer.visitIfStatement.<fn>.<fn>
package:async_await/src/xform.dart 1788       AsyncTransformer.visitBinaryExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1798       AsyncTransformer.visitBinaryExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1797       AsyncTransformer.visitBinaryExpression.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1793       AsyncTransformer.visitBinaryExpression.<fn>
package:async_await/src/xform.dart 1787       AsyncTransformer.visitBinaryExpression.<fn>.<fn>
package:async_await/src/xform.dart 1798       AsyncTransformer.visitBinaryExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1944       AsyncTransformer.visitIntegerLiteral.<fn>
package:async_await/src/xform.dart 1797       AsyncTransformer.visitBinaryExpression.<fn>.<fn>
package:async_await/src/xform.dart 2077       AsyncTransformer.visitPropertyAccess.<fn>.<fn>
package:async_await/src/xform.dart 1876       AsyncTransformer.visitPrefixedIdentifier.<fn>
package:async_await/src/xform.dart 2076       AsyncTransformer.visitPropertyAccess.<fn>
package:async_await/src/xform.dart 1793       AsyncTransformer.visitBinaryExpression.<fn>
package:async_await/src/xform.dart 1786       AsyncTransformer.visitBinaryExpression.<fn>
package:async_await/src/xform.dart 1151       AsyncTransformer.visitIfStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1556       AsyncTransformer.visitWhileStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1530       AsyncTransformer.visitVariableDeclarationStatement.<fn>.<fn>
package:async_await/src/xform.dart 1496       AsyncTransformer._translateDeclarationList.<fn>
package:async_await/src/xform.dart 1487       AsyncTransformer._translateDeclarationList.translateDecl.<fn>
package:async_await/src/xform.dart 2077       AsyncTransformer.visitPropertyAccess.<fn>.<fn>
package:async_await/src/xform.dart 2077       AsyncTransformer.visitPropertyAccess.<fn>.<fn>
package:async_await/src/xform.dart 1876       AsyncTransformer.visitPrefixedIdentifier.<fn>
package:async_await/src/xform.dart 2076       AsyncTransformer.visitPropertyAccess.<fn>
package:async_await/src/xform.dart 2076       AsyncTransformer.visitPropertyAccess.<fn>
package:async_await/src/xform.dart 1486       AsyncTransformer._translateDeclarationList.translateDecl
package:async_await/src/xform.dart 1511       AsyncTransformer._translateDeclarationList
package:async_await/src/xform.dart 1527       AsyncTransformer.visitVariableDeclarationStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 692        AsyncTransformer._translateStatementList
package:async_await/src/xform.dart 696        AsyncTransformer.visitBlock.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 829        AsyncTransformer.visitExpressionStatement.<fn>.<fn>
package:async_await/src/xform.dart 2040       AsyncTransformer.visitMethodInvocation.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1898       AsyncTransformer._translateExpressionList.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1917       AsyncTransformer._translateExpressionList
package:async_await/src/xform.dart 2038       AsyncTransformer.visitMethodInvocation.<fn>.<fn>
package:async_await/src/xform.dart 1885       AsyncTransformer.visitIndexExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1884       AsyncTransformer.visitIndexExpression.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1880       AsyncTransformer.visitIndexExpression.<fn>
package:async_await/src/xform.dart 2034       AsyncTransformer.visitMethodInvocation.<fn>
package:async_await/src/xform.dart 827        AsyncTransformer.visitExpressionStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1062       AsyncTransformer.visitForStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1530       AsyncTransformer.visitVariableDeclarationStatement.<fn>.<fn>
package:async_await/src/xform.dart 1496       AsyncTransformer._translateDeclarationList.<fn>
package:async_await/src/xform.dart 1487       AsyncTransformer._translateDeclarationList.translateDecl.<fn>
package:async_await/src/xform.dart 1885       AsyncTransformer.visitIndexExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1975       AsyncTransformer.visitSimpleStringLiteral.<fn>
package:async_await/src/xform.dart 1884       AsyncTransformer.visitIndexExpression.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1880       AsyncTransformer.visitIndexExpression.<fn>
package:async_await/src/xform.dart 1486       AsyncTransformer._translateDeclarationList.translateDecl
package:async_await/src/xform.dart 1511       AsyncTransformer._translateDeclarationList
package:async_await/src/xform.dart 1527       AsyncTransformer.visitVariableDeclarationStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 829        AsyncTransformer.visitExpressionStatement.<fn>.<fn>
package:async_await/src/xform.dart 2046       AsyncTransformer.visitMethodInvocation.<fn>.<fn>
package:async_await/src/xform.dart 1898       AsyncTransformer._translateExpressionList.<fn>
package:async_await/src/xform.dart 1999       AsyncTransformer.visitStringInterpolation.<fn>.<fn>
package:async_await/src/xform.dart 1898       AsyncTransformer._translateExpressionList.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1917       AsyncTransformer._translateExpressionList
package:async_await/src/xform.dart 1987       AsyncTransformer.visitStringInterpolation.<fn>
package:async_await/src/xform.dart 1917       AsyncTransformer._translateExpressionList
package:async_await/src/xform.dart 2045       AsyncTransformer.visitMethodInvocation.<fn>
package:async_await/src/xform.dart 827        AsyncTransformer.visitExpressionStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 1530       AsyncTransformer.visitVariableDeclarationStatement.<fn>.<fn>
package:async_await/src/xform.dart 1496       AsyncTransformer._translateDeclarationList.<fn>
package:async_await/src/xform.dart 1487       AsyncTransformer._translateDeclarationList.translateDecl.<fn>
package:async_await/src/xform.dart 1885       AsyncTransformer.visitIndexExpression.<fn>.<fn>.<fn>
package:async_await/src/xform.dart 1975       AsyncTransformer.visitSimpleStringLiteral.<fn>
package:async_await/src/xform.dart 1884       AsyncTransformer.visitIndexExpression.<fn>.<fn>
package:async_await/src/xform.dart 1872       AsyncTransformer.visitSimpleIdentifier.<fn>
package:async_await/src/xform.dart 1880       AsyncTransformer.visitIndexExpression.<fn>
package:async_await/src/xform.dart 1486       AsyncTransformer._translateDeclarationList.translateDecl
package:async_await/src/xform.dart 1511       AsyncTransformer._translateDeclarationList
package:async_await/src/xform.dart 1527       AsyncTransformer.visitVariableDeclarationStatement.<fn>
package:async_await/src/xform.dart 690        AsyncTransformer._translateStatementList.<fn>
package:async_await/src/xform.dart 692        AsyncTransformer._translateStatementList
package:async_await/src/xform.dart 696        AsyncTransformer.visitBlock.<fn>
package:async_await/src/xform.dart 636        AsyncTransformer.visitBlockFunctionBody
package:analyzer/src/generated/ast.dart 2902  BlockFunctionBody.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit
package:async_await/src/compiler.dart 45      compile
package:async_await/async_await.dart 10       compile
package:async_await/transformer.dart 25       AsyncAwaitTransformer.apply.<fn>
dart
:isolate                                  _RawReceivePortImpl._handleMessage
[Info from Dart2JS]:
Compiling Assek|web/assek.dart...

Alex Tatumizer

unread,
Mar 24, 2015, 9:41:26 PM3/24/15
to mi...@dartlang.org
Justin: though we agreed to disagree, I'm still trying to figure out WHY we don't need chain() in sync world, and (as I believe) need it in async world.
It's not that easy to verbalize, and the following may look more like scholastic rant, but still, I will try :)

One way to attack the problem is this: sync world is a narrow subset of async world. So narrow that it makes it possible for us to introduce domain-specific language that is quite concise and convenient *as long as we stay in the world of sync*. In the same way as to record chess games, we can use very condensed notation like e2 - e4. e7 - e5.

It so happened in programming that historically, we used to deal with sync programs much more than with async ones. All our programming vocabulary is "optimized" for this narrow case. (This is not so, say, in hardware, where parallel processes are a norm, and serial ones are exception).

Naturally, when we start dealing with async programs, we need more words than in "chess game". Using "chain" in sync world would be redundant because it's only chain, and nothing but chain. There's nothing analogous to "parallel" in "pure sync" world.

It took a long time to work out a vocabulary for sync world, though even this one is not frozen: new concepts still emerge from time to time.
But async programming is (relatively) new area. Language for it is not yet very well established. Hence the opportunity!.

And here there's a lot of room for personal tastes. I don't like ..then()..then()...then() - it is just verbose and noisy, you can't see the forest for the trees.
await .... await ... await..., is not much better. In both cases, there's Repetition, lots of it. (I'm repeating myself, too, sorry).





Cristian Garcia

unread,
Mar 24, 2015, 10:27:13 PM3/24/15
to mi...@dartlang.org
Id take the comonadic await over the monadic then on all circumstances. It just much simpler to pretend you are getting an actual value out of a function than getting it through a callback. A more generalized version of this is Haskell's do-notation: takes the pain from having to repeat >==/fmap on all monadic operations as you currently do with then.

Jim Trainor

unread,
Mar 25, 2015, 5:03:23 AM3/25/15
to mi...@dartlang.org
This doesn't have to be so complicated.  It is just a function call that happens when data is available or something has finished (i.e. the available data is null). It can be wrapped in all sorts of machinations all of which have their place. The original problem on this thread was simply that it didn't work!


On Tue, Mar 24, 2015 at 10:27 PM, Cristian Garcia <cgarc...@gmail.com> wrote:
Id take the comonadic await over the monadic then on all circumstances. It just much simpler to pretend you are getting an actual value out of a function than getting it through a callback. A more generalized version of this is Haskell's do-notation: takes the pain from having to repeat >==/fmap on all monadic operations as you currently do with then.

--

John Davis

unread,
Mar 25, 2015, 7:05:26 AM3/25/15
to mi...@dartlang.org
Sorry for your pain, but please don't trash the feature.  Dart is breaking some marvelous ground here.  After 1.9 hits, ping me and I'll try to make some samples.


On Friday, March 20, 2015, Rat Jo <jora...@gmail.com> wrote:

Since I started to use async/await, my life have become hell. Here is some the few reason why:

dart:core-patch/object_patch.dart 42          Object._noSuchMethod
dart:core-patch/object_patch.dart 45          Object.noSuchMethod
package:async_await/src/xform.dart 854        AsyncTransformer._translateSynchronousForEach
package:async_await/src/xform.dart 892        AsyncTransformer.visitForEachStatement
package:analyzer/src/generated/ast.dart 7003  ForEachStatement.accept
package:async_await/src/xform.dart 490        AsyncTransformer.visit
- As soon as you add one await somewhere, your whole program transform in a await/async hell/mess where you have to add them to almost all of your function, because I'm trying to use indexeddb, so every time you want to access your data, it's a "await".
- If you want to use IndexedDb, you don't have much choose then to use async/await.
- Sometime, just marking some function async make the compiler throwing the towel and give crazy number of error. You have to change the error of function, split function, change variable name, etc.. to eventually get your code working...
- You make unittest program to test your website? all of your function start with an await


It's have been since async/await have been available that I started to use them which is now almost three month and those problem didn't go away, not even with the latest 1.9.0-dev.10.10 (rev 44550).

So, I got one suggestion, if you think about starting to use await/async, don't do it.

--

Jim Trainor

unread,
Mar 25, 2015, 7:24:39 AM3/25/15
to mi...@dartlang.org
But Rat Jo's advice is correct. Don't use async/await yet for anything other then experimentation.  Especially if combined with indexed_db - my addition.  (There is a reason it is marked as "experimental" in the editor!)  Even when 1.9 is released I would be cautious about diving into it in conjunction with indexed_db because of the transaction/event-loop dependency. I'd want to go through a cycle of validation first. I'd want to completely understand the interactions between async/await and the browser event loop.
Reply all
Reply to author
Forward
0 new messages