This might not be in-scope, or at least not fit in to the flow of the narrative. But one thing that always struck me as interesting was whether calling a function should execute its body once or more than once.
For promises and async functions, the function's body is executed upon calling the function; calling .then on the return value observes it.
For (sync) generators and generator functions in JS, the function's body kind of "starts" upon calling the function, but immediately suspends until .next is called on the return value. This is because the function returns a generator, which is an iterable-iterator (i.e. an iterator whose [Symbol.iterator]() method returns this)
Notably, if you do
var g = genFun();
for (var i of g) { ... }
for (var j of g) { ... }
the body of genFun will only be called once, and in fact the second loop will immediately exit, doing nothing.
For (sync) "generator functions" in C# (which don't have yield-back-into capabilities), the function's body executes once for each time you iterate through it. This is because they return enumerables, not enumerators. So when you do
var enumerable = genFun();
foreach (var i in enumerable) { ... }
foreach (var j in enumerable) { ... }
the body of genFun will be called twice, with both loops going through the resulting sequences, because each loop gets its own enumerator from enumerable.
Jafar's proposal for async generators as observables resembles C# in this regard, with
var observable = asyncGenFun();
for (var i on observable) { ... }
for (var j on observable) { ... }
calling the body of asyncGenFun twice. Each for-on desugars to a call to observable.observe({ next, throw, return }), where each concurrently-executing body of asyncGenFun calls into their respective { next, throw, return } tuples.
I'd love a discussion about what tradeoffs are involved here, perhaps related to iterables vs. iterators.
This might not be in-scope, or at least not fit in to the flow of the narrative. But one thing that always struck me as interesting was whether calling a function should execute its body once or more than once.
For promises and async functions, the function's body is executed upon calling the function; calling
.then
on the return value observes it.For (sync) generators and generator functions in JS, the function's body kind of "starts" upon calling the function, but immediately suspends until
.next
is called on the return value. This is because the function returns a generator, which is an iterable-iterator (i.e. an iterator whose[Symbol.iterator]()
method returnsthis
)Notably, if you do
the body of
genFun
will only be called once, and in fact the second loop will immediately exit, doing nothing.For (sync) "generator functions" in C# (which don't have yield-back-into capabilities), the function's body executes once for each time you iterate through it. This is because they return enumerables, not enumerators. So when you do
the body of
genFun
will be called twice, with both loops going through the resulting sequences, because each loop gets its own enumerator fromenumerable
.Jafar's proposal for async generators as observables resembles C# in this regard, with
calling the body of
asyncGenFun
twice. Eachfor-on
desugars to a call toobservable.observe({ next, throw, return })
, where each concurrently-executing body ofasyncGenFun
calls into their respective{ next, throw, return }
tuples.I'd love a discussion about what tradeoffs are involved here, perhaps related to iterables vs. iterators.