> > No, that's not the case. That code was not hypothetical: it works in > SpiderMonkey using extensions that have been around for several years. You > might want to take some time to explore generators by following the docs > that Mike linked to, and by playing with SpiderMonkey. >
OK, clearly I have a lot to learn about SpiderMonkey and extended JavaScript stuff like that. I'm sorry I'm so behind the game. I'll try to catch up :) > Both "single-frame continuation" and "shallow continuation" are terms we've > used informally for the same idea: being able to suspend a single function > activation (aka stack frame) as a JavaScript value that you can use later to > resume the suspended activation. > The wording "suspend ...as a JavaScript value you can use" seems to me to indicate that a defered-promise/yielded-function is a first-class JavaScript value type, that can be assigned and manipulated. Is that correct? Which also seems to possibly imply that the code that calls a function is in control of suspending the function and of resuming it? I may obviously be mis-interpreting, but I'd say my idea is a little more reserved than that. There is no first-class "Promise" type. It's just an implicit mechanism by which the asynchronous negotiation of each subsequent expression of the @ statement occurs. Put another way, every function (and indeed every valid expression) call has a "promise". A function (and only a function) called can choose to defer its internal promise. If a function call doesn't defer its promise, or if the expression is not a function call, then the promise for that expression is immediately flagged as fulfilled. But the calling code doesn't interact with the promise directly. That is, a function doesn't return a first-class promise value that the calling code directly receives and manipulates. A function can only flag its own internal state as being deferred. A function that flags itself as deferred can still do a normal `return` statement and send back an immediate value to the calling code statement/expression. For instance: function foo() { var p = promise; setTimeout(function(){ p.fulfill(); }, 1000); p.defer(); return 12; } function bar() { console.log(x+1); } var x = 0; (x = foo()) @ bar(); console.log(x); This code example would immediately output "12", and then a second later, output "13". The calling code only indirectly knows of a function call's promise deferral, via the @ operator. The @ operator is able to inspect if the previous function call's internal promise was deferred or not, and if it was deferred, the rest of that current @ statement in the calling code is suspended. Otherwise, the statement continues its evaluation immediately. When the deferred function signals that its now complete, the suspended @ statement receives that signal and resumes evaluation of the statement. The function code doesn't "suspend" itself or create a continuation inside itself. It simply can flag (with `defer()`) that it won't be finished yet when function return occurs. And the function hands the "key" (with `fulfill()`) to fulfilling its promise over to some asynchronously executing code -- for instance, inside an inner function that's assigned as a callback for an event, XHR call, or timeout, etc. If a function call doesn't flag that it will defer its completion, it is always assumed to have an immediate completion, which means that any standard function call in an @ statement will simply keep going with no suspension of the statement at that point. > I don't understand the |promise| "auto-variable" you mention. What does it > do? Does it affect control flow as well, or is it no difference from (new > Promise()) for some built-in Promise constructor? (BTW, automatically-bound > variables like |arguments| are a mis-feature IMO, and I'd urge you to > reconsider that part.) > `promise` as an auto-variable is a special accessor to that current function call's internal promise state. It has `fulfill()`, `fail()` and `defer()` as its 3 methods. It also has a `messages` property, which is an array of the arguments passed to the previous deferred function's `fulfill(...)` or `fail(...)` call. If there is no message (either an implied promise from an expression or normal function call, or no parameters passed, then the `messages` is empty. The reason it's not just `new Promise()` is because its not an object that is negotiable (can't be returned, etc). It only has meaning inside the context of the function call. I'm not wild about having to create another auto-variable either. But `this` isn't sufficient since it takes on a function's activation object, and `arguments.callee` is deprecated. I need some way to have a function refer to its own internal promise state. I'd welcome ideas for a different name for it, or some other way to access this internal state that's not so awkward. > What does it mean when you say in your post that "the @ operator will wait > to continue"? What does it mean in JS to "wait?" Does it mean that > evaluation of the entire statement suspends Yes. > and the result is a new promise? No. The "result" of a suspended statement would be the the last immediate return value from a function call (or the implied `undefined` if the function didn't have a `return`), or from the expression (like `b=5` or `d++`, etc). Since my idea doesn't model promises as a first-class value returned from the function, but just as internal state of the function call, it wouldn't make any sense to have that promise be the statement's value. > You mention a ternary form but I can't find it anywhere in the blog post. > Do you describe it in any more detail somewhere else? > Sorry, the ternary form is illustrated on the original gist thread where I first proposed this idea: https://gist.github.com/727232#file_ex2:extend...@_:_usage Essentially: function foo() { setTimeout(function(){ if (blah == 5) { p.fulfill(); } else { p.fail(); } }, 1000); } function yay() { console.log("yay"); } function bummer() { console.log("bummer"); } var blah = 5; foo() @ yay() : bummer(); // after 1 second, "yay" ---- foo() @ yay() : bummer(); // after 1 second, "bummer" blah = 10; > What is the specification of p.defer()? Does it cause its containing > function to suspend? Or just its containing statement? > The `p.defer()` doesn't create any kind of side effect inside the function. It doesn't suspend the function or create a continuation. It simply flag's that function's internal promise state that it will be deferred, and that at a later time, `fulfill()` or `fail()` will be called to complete the promise. Some have suggested that "fail" not be an explicit thing but only if a JavaScript error/exception is thrown. I don't suppose I'd be terribly opposed to that, but I do see some complications with it. First, if I programmatically want to trigger the "fail" path, then I have to artificially create a JS error with `throw`. That's a little more awkward than just calling `fail`, especially since I can directly call `fulfill` in the same context. Also, if I want to pass some sort of value other than an error object as my "message" to the "fail" path, I have to wrap that message inside the Error object I throw. Again, more awkward. `fail()` seems more direct to me. --Kyle
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss