kriskowal / gtor

A General Theory of Reactivity
MIT License
3.03k stars 109 forks source link

Talk about the issue of generator objects and their relation to function calls? #9

Closed domenic closed 10 years ago

domenic commented 10 years ago

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.