>
> 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

Reply via email to