How to return a lazy Iterable from an async function

Viewed 116

My goal is to asynchronously return a lazy Iterable created by a generator function. I don't want to return a Stream or use the asnyc* generator since the generation can be done synchronously, only some previous code needs to run asynchronously.

Currently I'm doing it like this, but I wonder if there is any better way to do this? If this is the only option I probably should outsource the generator function.

Future<Iterable<String>> someAsyncFunction() async {
  // some async task
  await Future.delayed(Duration(seconds: 1));
  
  Iterable<String> x () sync* {
    for (var s in ['1', 'b', 'c']) {
      yield s;
    }
  }
  return x();
}

print(await someAsyncFunction());

I was using a self invoked function before, but I wasn't able to specify a return type on it so I changed it to the code above.

Future<Iterable<String>> someAsyncFunction() async {
  // some async task
  await Future.delayed(Duration(seconds: 1));
  
  return () sync* {
    for (var s in ['1', 'b', 'c']) {
      yield s;
    }
  }();
}
1 Answers

Your approach looks perfectly fine.

What I'd probably do myself is to have the function creating the literal as a helper function outside the async function:

Future<Iterable<String>> someAsyncFunction() async {
  // some async task
  await Future.delayed(Duration(seconds: 1));
  return _iterateTheValues(the, values);
}

Iterable<String> _iterateTheValues(Some the, Other values) sync* {
  for (var s in combine(the, values)) { // or use yield*.
    yield s;
  }
}

If you can create a useful iterable from some values after doing an asynchronous operation to find those values, it seems plausible that you'll eventually want to do the same thing with existing values. Maybe just for testing, maybe using a cache. It just feels like the synchronous iteration could be a thing of its own, separate from the asynchronous initialization needed for it.

Related