<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Sep 5, 2011, at 9:36 PM, John J Barton wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">On Sun, Sep 4, 2011 at 1:42 PM, Brendan Eich <span dir="ltr"><<a href="mailto:brendan@mozilla.com">brendan@mozilla.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div style="word-wrap:break-word"><div><div class="im"><div>On Sep 4, 2011, at 11:06 AM, John J Barton wrote:</div><br><blockquote type="cite"><div class="gmail_quote">As a reader I have to parse the function carefully to look for the 'yield'. If I find one, then I know that this is not actually a function after all. Then I need to mentally draw a line after the yield and label it "entry-point #2".<br>
</div></blockquote><div><br></div></div>This is addressed in ES6 by changing the head of the generator function as follows:</div><div><br></div><div><div class="im"><pre><code>spawn(function* () {
    try {
        var [foo, bar] = yield join(read("foo.json"),
                                    read("bar.json")).timeout(1000);
        render(foo);
        render(bar);
    } catch (e) {
        console.log("read failed: " + e);
    }
});<br></code></pre></div></div></div></blockquote><div> (For others who have some trouble seeing the difference, here the function keyword is followed by the multiplication symbol).<br><br>"generator() {}" would make a lot more since to me, it would more clearly alert the reader at no added cost for the writer, as well as helping new users of this feature separate it's effect from functions.<br></div></div></blockquote><div><br></div>We considered that, but generator is not reserved, and reserving it in ES6 requires newline sensitivity at least. Consider an anonymous generator similar to the one you typed:</div><div><br></div><div>  generator()</div><div>  {...}</div><div><br></div><div>where ... is actual code (and the {...} style may use multiple lines and indentation). This could be valid code in the field today, relyling on ASI to insert the semicolon after "generator()".</div><div><br></div><div>What's more, the precedent in Python is not a negative or a trivial benefit. Besides reusing brain-print, we stand on field-tested design in a similar language. Python uses def for both functions and generators.</div><div><br></div><div><br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin-top: 0pt; margin-right: 0pt; margin-bottom: 0pt; margin-left: 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex; position: static; z-index: auto; "><div style="word-wrap: break-word;"><div><div class="im"><blockquote type="cite"><div class="gmail_quote">Next I have to read through the source of spawn() and track the lifetime-of and references-to the object it received, seeking calls to send().</div>
</blockquote><div><br></div></div>No, you can use spawn as a black box. It's an API entry point to the taskjs library. You do not need to read the source to use an API.</div></div></blockquote><div> </div><div><span><span class="type">Hmm., the doc <a href="http://dherman.github.com/taskjs/doc/api.html">http://dherman.github.com/taskjs/doc/api.html</a> says:<br>
  Task </span><span class="funcName">spawn</span>(<span class="params"><span class="type">generator function </span><span class="name">thunk</span></span>)<br>But as I understand it, the send() plays a role in the API to spawn correct?<br></span></div></div></blockquote><div><br></div>The value sent to yield expressions in your generator, yes. So? Again that does not mean you must read the inside of the black box. The API docs may be lacking, of course :-|.</div><div><br></div><div><br><blockquote type="cite"><div class="gmail_quote"><div><span>
</span><br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><div style="word-wrap: break-word;"><div><br></div><div><div class="im"><br>
<blockquote type="cite"><div class="gmail_quote">Assuming I am understanding the idea, then my description above is also my criticism: control and data flow is jumping around in unusual ways and functions morph into multi-entry point things with new API.<br>
</div></blockquote><div><br></div></div>There's no free lunch. Either we renounce adding new syntax by which to capture a shallow continuation, which leaves us with the nested callback function world of today, which people object to on several grounds:</div>
<div><br></div><div>* Nesting makes hard-to-read, rightward-drifting function spaghetti.</div><div><br></div><div>* Nesting increases the risk of capturing too much environment, potentially entraining memory for a long time -- bloat and leak bugs.</div>
<div><br></div><div>These are not unmanageable according to some JS hackers, but they are not trivial problems either. They keep coming up, in the Node community and among browser JS developers. They're real.</div></div>
</blockquote><div><br>So it is known that no alternative exists beyond these two choices?<br></div></div></blockquote><div><br></div>On this list, we have been over the design space many times. Please search for call/cc and "shallow continuations" using site:mail.mozilla.org. I'm short on time now.</div><div><br></div><div>The upshot is that you're suggesting threads, or deep continuations. Threads suck, we are not exposing JS developers to preemptively scheduled threads in a language with shared-object mutation and therefore significant data races.</div><div><br></div><div>Deep continuations have two problems:</div><div><br></div><div>1. They break the ability to reason about loss of invariants due to an event loop turn being taken under what looks like a function call.</div><div><br></div><div>2. The second problem is that different implementations will not agree on capturing deep continuations across native frames, but interoperation demands one standards. Forbidding capture across native frames breaks abstraction over self-hosted vs. native code (e.g. Array map calling its downward funarg). Requiring will mean that some VMs won't be able to conform to such a spec -- Java, .NET, any without hand-coded magic to deal with compiler magic involving native frame representation.</div><div><br></div><div>This leaves shallow continuations, and generators won out in a fair fight with a more minimal "shift" proposal for shallow continuations (too minimal).</div><div><br></div><div>Generators share with private name objects a right-sized (minimal but not too small) gap-filling quality that supports all of:</div><div><br></div><div>* prompt standardization,</div><div>* interoperable implementation, and</div><div>* library ecosystem builder upside far beyond what TC39 could ever do on any schedule.</div><div><br></div><div>They're in ES6 for good reason.</div><div><br></div><div>/be</div></body></html>