Re: natively negotiating sync vs. async...without callbacks
I really like the proposal, but think the syntax is confusing many of us. I think that the proposal is closer to post hooking than continuation in spirit. It appears that the syntax is misleading but reading the text of the desired effects promise.defer() is acting like a point to hook the next part of the expression rather than a yield (not sure if it would make more sense to make this construct in whatever syntax return from the current function). The reason that I believe this is the case is the fact that the stack is unwound / normal closure abnormalities apply it seems. The interesting part of this proposal is the fact that you can pass messages between hooks to me. Overall, I find a hooking proposal to be beneficial since soo many times I am making anonymous functions to do so. Having to declare a hooking point might be overkill, but the message passing and a generic code pathing on error would be amazing for async dev time personally. I think given the side effects wanted these are the list of features in this proposal: 1. code run in this statement does so at the first opportune moment (sync runs immediately) 2. code in this statement does not start execution until some condition is true 3. code that encounters and error in this statement is routed to a construct in this statement automatically. Given these I propose a different syntax, since #2 is the main issue with why it is being considered similar to a continuation. I think that this construct should declare up front instead of inline when it defers. This syntax is still poor but should help to illustrate (using a binary ! since js doesnt have one). foo = function(cb) { setTimeout(cb,1000) } bar = function(cb) { ... cb(1) ... } end = function(cb,x) { log(x) } // will log 1 foo @ bar @ end ! err Would mean that foo should wait until cb is fired in defer. Then if it does not error it would go to bar and pass along some context arguments. If it errors it would go to err. If bar does not error it would go to end. If bar errors it would go to err still. So how does this relate to making things easier? 1. Error routing callbacks. This would be a god send if you have ever used node.js . 2. No confusing continuations (many people like them but I find them hard to track code wise). 3. Passing data between callbacks would not require a closure construction which is generally costly. 4. What is being defered on does not break functions since it is an argument automatically passed (non-ideal since it could cause issues with existing code). Like Kyle proposed a keyword maybe needed etc. Cheers, Bradley On Thu, Dec 9, 2010 at 9:09 PM, Brendan Eich bren...@mozilla.com wrote: On Dec 9, 2010, at 3:27 PM, David Herman wrote: I'm not trying to open the can-o'-worms around block level changes. The above code suggests that a 'yield' suspension of execution is local to the nearest container { } block, in this case the try { } block. No, that's not the case. That code was not hypothetical: it works in SpiderMonkey using extensions that have been around for several years. Works in Rhino too, thanks to Norris Boyd, Steve Yegge, et al. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
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
Re: natively negotiating sync vs. async...without callbacks
I think given the side effects wanted these are the list of features in this proposal: 1. code run in this statement does so at the first opportune moment (sync runs immediately) 2. code in this statement does not start execution until some condition is true 3. code that encounters and error in this statement is routed to a construct in this statement automatically. There's some other really important aspects of my proposal: 4. Control of execution (that is, the actuall calling of a function) is linear in the chain in the calling code, rather than being controlled by the code inside a function. If some function in my chain is a third-party function I don't control and don't fully trust, then I don't want to pass it any references to my code's functions (as a callback) or any of my code's variables/scope. I simply want that function to signal to my code that it's complete. My code then is able to wait for that signal (if I chose to set up the statement that way with @ usage) and then continue evaluation of the rest of the statement. For instance: function foo() { var p = promise; setTimeout(function(){ p.fulfill(20); }, 1000); p.defer(); // this could be p.willDefer = true or some other less confusing syntax, // for flagging the current function's internal promise as being deferred. } Now, let's assume that function is a third party code that I don't control. All I know that it's async/promise aware. Now, let's also assume I have a `bar` function in my code that I need to pass an object to and have it do something, but I only want `bar` to run after `foo` completes. In other words, I want to kind of conceptually observe the async behavior of `foo` and subscribe to his completion event. But I don't know or trust `foo` enough to pass him any of my functions, nor do I want to pass him references to any of my scope's variables (which he could then mess with). I just want to listen for him to signal that he's fully complete, and then move on. function bar(y) { console.log(y.some_value); } var obj = { some_value: 10 }; foo() @ bar(obj); // whenever `foo` completes, output: 10 5. I don't want to conflate a function's parameters, or its return value, with the negotiation of the asynchronous chaining, suspension, resume, message passing, etc. This is intended to preserve existing code to the greatest extent possible. For instance: function foo(x) { var p = promise; setTimeout(function(){ p.fulfill(x+20); }, 1000); p.defer(); return x+10; // return an immediate value } Again, let's assume that function is a third party code that I don't control. All I know that it's async/promise aware, and that it has both an immediate return value and a deferred result. Let's then say that in some part of my code, I just want to get the immediate value, and I don't care what that function's eventual/deferred result is: var x = foo(4); console.log(x); // 14 ... This code would operate exactly like normal JavaScript. Even though foo() has a deferred part to it, the calling code is choosing not to observe this behavior, and just continue as normal, effectively discarding any async behavior that may or may not be inside of `foo`. This is identical to existing code patterns where I can call a function, and it can create async side effects that I may or may not be aware of or care about. Later in the code, I may decide that I do actually want to care about the `foo` function's async behavior, so I want to construct a statement that explicitly observes `foo` and waits for that fulfilled value. Without needing any kind of different/changed `foo` signature in any way, I can then choose to do this: function bar(y) { var _x = (promise.messages.length) ? promise.messages[0] : 1; console.log(_x * y); } bar(3); // immediately, 3 var x; (x = foo(4)) @ bar(3); // after 1 second: 42 console.log(x); // but, immediately: 14 I recognize the syntax I'm proposing is quite different from normal code (but I'm hoping eventually that it's seen as different in a good way, not a confusing or bad way). But the syntax is explicitly and intentionally separating the concern of async promise/deferral and fulfillment/continuation from the concern of function parameter passing or function return values. I think I should be able to choose in my calling code if I want to construct an @ statement that observes the deferral or if I just want to call the function and only observe its immediate effects. This is conceptually the same as me saying that if there's some function I want to call that requires a callback, but for whatever reason I don't care about the eventual effects, I can just pass it a dummy no-op callback and accomplish the ignoring (the not observing) of that async effect. Given these I propose a different syntax, since #2 is the main issue with why it is being considered similar to a continuation. I think that this construct should declare up
Re: natively negotiating sync vs. async...without callbacks
Lastly, I'd say that function signatures which currently accept a callback also don't *have* to change. In fact, there may be some value in allowing both styles (existing callbacks, and my new proposed style) to co-exist in the same function, giving the calling developer the freedom to choose. Another example of this would be existing interfaces in JavaScript which accept callbacks, like `setTimeout`. Those interfaces could be extended to also be aware of this new behavior, without changing their function signature at all: function foo() { console.log(foo rocks); } setTimeout(foo, 1000); // or setTimeout(null, 1000) @ foo(); --Kyle ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
4. Control of execution (that is, the actuall calling of a function) is linear in the chain in the calling code, rather than being controlled by the code inside a function. Another reason I feel it's important to address being able to retain control of the execution of the chained functions in *my* calling code is the awkwardness around function context objects and them losing their `this` binding. We know that this: function foo(cb) { setTimeout(cb,1000); } var obj = { val: 1, bar: function() { this.val = (this.val || 0) + 1; console.log(this.val); } }; foo(obj.bar); ...is subject to the `this` binding being lost from obj and becoming window. So, we have to go through hoops to bind a function's `this` tightly, with Function.prototype.bind(), or we create a manual anonymous function wrapper, etc. While it's possible to correct for, obviously, it creates extra work for the developer and is a common trap for subtle errors. Instead: foo() @ obj.bar(); Since my calling code is in control of the execution of `bar`, I call it on the proper object and `this` doesn't get lost. --Kyle ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
I pretty much abandoned that line of investigation with the conclusion that generators: http://wiki.ecmascript.org/doku.php?id=strawman:generators are a good (and well-tested, in Python and SpiderMonkey) design for single-frame continuations. They hang together well; in particular, they don't have the issues with `finally' that some of the alternatives I talked about do. Moreover, the continuation-capture mechanisms based on call/cc or shift/reset require additional power in the VM to essentially tail-call their argument expression. When I tried prototyping this in SpiderMonkey, I found this to be one of the biggest challenges -- and that was just in the straight-up interpreter, not in the tracing JIT or method JIT. Generators work well for lightweight concurrency. As a proof of concept, I put together a little library of tasks based on generators: http://github.com/dherman/jstask Somebody reminded me that Neil Mix had written a very similar library several years ago, called Thread.js: http://www.neilmix.com/2007/02/07/threading-in-javascript-17/ and there's another library called Er.js that built off of that to create some Erlang-like abstractions: http://www.beatniksoftware.com/erjs/ Dave On Dec 8, 2010, at 11:36 PM, Tom Van Cutsem wrote: The spirit of the proposal is that this special type of statement be a linear sequence of function executions (as opposed to nested function-reference callbacks delegating execution to other code). The special behavior is that in between each part/expression of the statement, evaluation of the statement itself (NOT the rest of the program) may be suspended until the previous part/expression is fulfilled. This would conceptually be like a yield/continuation localized to ONLY the statement in question, not affecting the linear execution of the rest of the program. This reminds me of a proposal by Kris Zyp a couple of months ago (single frame continuations) https://mail.mozilla.org/pipermail/es-discuss/2010-March/010865.html I don't think that discussion lead to a clear outcome, but it's definitely related, both in terms of goals as well as in mechanism. I also recall it prompted Dave Herman to sketch the design space of (single-frame) continuations for JS: https://mail.mozilla.org/pipermail/es-discuss/2010-April/010894.html Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
PS To be concrete, here's an example code snippet using my jstask library that chains several event-generated actions together in a natural way (i.e., in direct style, i.e. not in CPS): var task = new Task(function() { var request = new HttpRequest(); try { var foo = yield request.send(this, foo.json); var bar = yield request.send(this, bar.json); var baz = yield request.send(this, baz.json); } catch (errorResponse) { console.log(failed HTTP request: + errorResponse.statusText); } ... foo.responseText ... bar.responseText ... baz.responseText ... }); I should also point out that the core of jstask is 7 lines of code. :) Dave On Dec 9, 2010, at 7:55 AM, David Herman wrote: I pretty much abandoned that line of investigation with the conclusion that generators: http://wiki.ecmascript.org/doku.php?id=strawman:generators are a good (and well-tested, in Python and SpiderMonkey) design for single-frame continuations. They hang together well; in particular, they don't have the issues with `finally' that some of the alternatives I talked about do. Moreover, the continuation-capture mechanisms based on call/cc or shift/reset require additional power in the VM to essentially tail-call their argument expression. When I tried prototyping this in SpiderMonkey, I found this to be one of the biggest challenges -- and that was just in the straight-up interpreter, not in the tracing JIT or method JIT. Generators work well for lightweight concurrency. As a proof of concept, I put together a little library of tasks based on generators: http://github.com/dherman/jstask Somebody reminded me that Neil Mix had written a very similar library several years ago, called Thread.js: http://www.neilmix.com/2007/02/07/threading-in-javascript-17/ and there's another library called Er.js that built off of that to create some Erlang-like abstractions: http://www.beatniksoftware.com/erjs/ Dave On Dec 8, 2010, at 11:36 PM, Tom Van Cutsem wrote: The spirit of the proposal is that this special type of statement be a linear sequence of function executions (as opposed to nested function-reference callbacks delegating execution to other code). The special behavior is that in between each part/expression of the statement, evaluation of the statement itself (NOT the rest of the program) may be suspended until the previous part/expression is fulfilled. This would conceptually be like a yield/continuation localized to ONLY the statement in question, not affecting the linear execution of the rest of the program. This reminds me of a proposal by Kris Zyp a couple of months ago (single frame continuations) https://mail.mozilla.org/pipermail/es-discuss/2010-March/010865.html I don't think that discussion lead to a clear outcome, but it's definitely related, both in terms of goals as well as in mechanism. I also recall it prompted Dave Herman to sketch the design space of (single-frame) continuations for JS: https://mail.mozilla.org/pipermail/es-discuss/2010-April/010894.html Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
It might surprise some who know me to hear this, but I agree with Dave on this. There's a huge gap between the single-frame mechanism and going the whole hog. Going all out does buy you some expressive power, but at the cost of complicating everything. If the simple mechanism gives you most of what you want (and I feel it goes pretty far), why commit to a lifetime of pain? Shriram ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 The generators from JS 1.7 are too specific to provide much help with promises, IMO. Adding a yield operator fundamentally alters the semantics of the entire surrounding function, violating the principle of locality. Consequently you need special mechanisms (like Neil's library) to even call an async function, and you can't return values either (with the return operator). Solving these problems was the point behind the shallow continuation proposal that we worked on. Does the generator strawman build on that work, or does it still fail to preserve locality? My understanding of Kyle's proposal was that he did not want to introduce real continuations, but this was more of a syntax for a specialized callback chain, reducing the verbosity of anon functions, callback registration. I'd prefer more of a generalized solution for reducing the size of anon functions (which has been discussed to great lengths here in the lambda threads). However, my belief on async is that the verbosity is only part of the pain, working with async within various control flows (loops, branches, etc) is more of a burden, hence the need for continuations (shallow/single frame, of course). Kris On 12/9/2010 8:55 AM, David Herman wrote: I pretty much abandoned that line of investigation with the conclusion that generators: http://wiki.ecmascript.org/doku.php?id=strawman:generators are a good (and well-tested, in Python and SpiderMonkey) design for single-frame continuations. They hang together well; in particular, they don't have the issues with `finally' that some of the alternatives I talked about do. Moreover, the continuation-capture mechanisms based on call/cc or shift/reset require additional power in the VM to essentially tail-call their argument expression. When I tried prototyping this in SpiderMonkey, I found this to be one of the biggest challenges -- and that was just in the straight-up interpreter, not in the tracing JIT or method JIT. Generators work well for lightweight concurrency. As a proof of concept, I put together a little library of tasks based on generators: http://github.com/dherman/jstask Somebody reminded me that Neil Mix had written a very similar library several years ago, called Thread.js: http://www.neilmix.com/2007/02/07/threading-in-javascript-17/ and there's another library called Er.js that built off of that to create some Erlang-like abstractions: http://www.beatniksoftware.com/erjs/ Dave On Dec 8, 2010, at 11:36 PM, Tom Van Cutsem wrote: The spirit of the proposal is that this special type of statement be a linear sequence of function executions (as opposed to nested function-reference callbacks delegating execution to other code). The special behavior is that in between each part/expression of the statement, evaluation of the statement itself (NOT the rest of the program) may be suspended until the previous part/expression is fulfilled. This would conceptually be like a yield/continuation localized to ONLY the statement in question, not affecting the linear execution of the rest of the program. This reminds me of a proposal by Kris Zyp a couple of months ago (single frame continuations) https://mail.mozilla.org/pipermail/es-discuss/2010-March/010865.html I don't think that discussion lead to a clear outcome, but it's definitely related, both in terms of goals as well as in mechanism. I also recall it prompted Dave Herman to sketch the design space of (single-frame) continuations for JS: https://mail.mozilla.org/pipermail/es-discuss/2010-April/010894.html Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org mailto:es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss - -- Kris Zyp SitePen (503) 806-1841 http://sitepen.com -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk0BA5kACgkQ9VpNnHc4zAy7nwCeJxL8Or+BUkYzfAi46EKEQG+O nGEAn0nCErWiI5mbunUwD860Czeof1bt =fHWD -END PGP SIGNATURE- ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
var task = new Task(function() { var request = new HttpRequest(); try { var foo = yield request.send(this, foo.json); var bar = yield request.send(this, bar.json); var baz = yield request.send(this, baz.json); } catch (errorResponse) { console.log(failed HTTP request: + errorResponse.statusText); } ... foo.responseText ... bar.responseText ... baz.responseText ... }); This style is similar to what I'm proposing, except for a few important things: 1. I'm not trying to open the can-o'-worms around block level changes. The above code suggests that a 'yield' suspension of execution is local to the nearest container { } block, in this case the try { } block. While I wouldn't be strongly opposed to it, it seems a little unnatural to have to wrap a collection of like-behaving stuff in a { }... if that were the case, just use an anonymous function (without or without the shorter syntax) and not have to change the meaning of { } blocks. But I can see some merit in this concept. Just not hugely in favor of it. 2. It breaks a fundamental thing that *I* happen to think is really important... it puts the control of whether a function is yielded or not into the hands of the calling code. I happen to think the function call itself should get to decide if he wants to yield asynchronously, or finish synchronously. For instance, imagine a function that retrieves a value from some database, but employs some memoization/local caching. In the first call case, that function will need to return asynchronously. But in the cached case, that function can and should return immediately. It'd be nice for the function to get to decide conditionally if it wants to yield or defer itself based on that state. And the calling code, by virtue of something like the native operator I suggested, can be written just one way and not care about that hidden detail. lookupDBValue(something) @ printValue(); For async, `printValue` will be held up from executing until `lookupDBValue` signals that it's complete by fulfilling its promise. For sync, `lookupDBValue` will already have its promise fulfilled at the time it returns, so the @ can move to immediately/synchronously executing `printValue`. --Kyle ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
This reminds me of a proposal by Kris Zyp a couple of months ago (single frame continuations) https://mail.mozilla.org/pipermail/es-discuss/2010-March/010865.html I don't think that discussion lead to a clear outcome, but it's definitely related, both in terms of goals as well as in mechanism. I also recall it prompted Dave Herman to sketch the design space of (single-frame) continuations for JS: https://mail.mozilla.org/pipermail/es-discuss/2010-April/010894.html I have to throw up a red flag and claim some naivety/ignorance here. Even after reading those links, I'm confused on what single frame continuations means. Perhaps what I have in mind is like that, but perhaps not, and I need a little help in understanding better the implications of that terminology. what is a single-frame? I *think* I roughly understand a 20,000ft level idea of what continuation is. It might surprise some who know me to hear this, but I agree with Dave on this. There's a huge gap between the single-frame mechanism and going the whole hog. Going all out does buy you some expressive power, but at the cost of complicating everything. If the simple mechanism gives you most of what you want (and I feel it goes pretty far), why commit to a lifetime of pain? As I said, I'm confused, so I'm not sure where my idea fits in the spectrum of what you're suggesting. Is my idea closer to the simple mechanism single-frame continuation side or is it closer to the whole hog side? I feel like my idea is pretty simple and limited compared to what I've seen from the broader scope ideas of full program continuations, true concurrency, etc. But maybe I'm in completely the wrong frame of reference and my idea is way far out there in complexity? Solving these problems was the point behind the shallow continuation proposal that we worked on. Does the generator strawman build on that work, or does it still fail to preserve locality? OK, so is shallow continuation the same as single-frame continuation or are we now talking about different concepts? Again, on the surface, shallow continuation sounds like it might be akin to what my idea is, but I may be completely wrong. My understanding of Kyle's proposal was that he did not want to introduce real continuations, but this was more of a syntax for a specialized callback chain, reducing the verbosity of anon functions, callback registration. In my naive understanding of the words, I think what I want to introduce is statement-localized continuations. I want for a statement, which can consist of two or more expressions, any or all of them being function calls which can chose to yield/defer/suspend their completion asynchronously. Only a statement which would use the @ operator on two or more expression operands would be able to take advantage of this statement localized continuation, though. A function that called `p.defer()` inside itself, but which was called in a normal expression/statement without @ operator, would simply complete and program execution would continue as normal. Of course, the function would still be able to complete asynchronously at a later time, just like a callback to setTimeout can. function foo() { console.log(foo); } function bar() { console.log(bar); } foo() @ bar(); // normal sync statement that prints foobar. function foo() { var p = promise; setTimeout(function(){ console.log(foo); p.fulfill(); },1000); p.defer(); } function bar() { console.log(bar); } foo() @ bar(); // async statement, which will print foobar, but not until 1000ms from now. And what I mean by statement-localized continuation is that yield/defer/suspend/continuation would only affect that single statement with the @ in that case, and any statements after the @ statement would continue synchronously if the @ statement indeed gets suspended at any point during its evaluation. So: function baz() { console.log(baz); } baz() @ foo() @ bar(); console.log(yes); would result in bazyes immediately, and 1000ms from now, foobar right after it. Does that make any more sense in terms of clarifying my idea, or does it just complicate things worse? --Kyle ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
On Dec 9, 2010, at 3:27 PM, David Herman wrote: I'm not trying to open the can-o'-worms around block level changes. The above code suggests that a 'yield' suspension of execution is local to the nearest container { } block, in this case the try { } block. No, that's not the case. That code was not hypothetical: it works in SpiderMonkey using extensions that have been around for several years. Works in Rhino too, thanks to Norris Boyd, Steve Yegge, et al. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
The spirit of the proposal is that this special type of statement be a linear sequence of function executions (as opposed to nested function-reference callbacks delegating execution to other code). The special behavior is that in between each part/expression of the statement, evaluation of the statement itself (NOT the rest of the program) may be suspended until the previous part/expression is fulfilled. This would conceptually be like a yield/continuation localized to ONLY the statement in question, not affecting the linear execution of the rest of the program. This reminds me of a proposal by Kris Zyp a couple of months ago (single frame continuations) https://mail.mozilla.org/pipermail/es-discuss/2010-March/010865.html I don't think that discussion lead to a clear outcome, but it's definitely related, both in terms of goals as well as in mechanism. I also recall it prompted Dave Herman to sketch the design space of (single-frame) continuations for JS: https://mail.mozilla.org/pipermail/es-discuss/2010-April/010894.html Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: natively negotiating sync vs. async...without callbacks
On Wed, Dec 8, 2010 at 8:48 AM, Getify Solutions get...@gmail.com wrote: I am aware that I'm kicking a potentially angry beehive by bringing up this topic, but I wanted to just have some discussion around if there's any possibility that JavaScript can, in the near term, have a native mechanism added to it for better managing of sync vs. async coding patterns, without nested callbacks. snip http://blog.getify.com/2010/12/native-javascript-sync-async/#proposal Briefly, in summary, I'm suggesting a statement like this in JavaScript: X(1,2)Y(3,4)Z(foo); `X`, `Y`, and `Z` are all possibly function calls which will not complete synchronously, but may defer their fulfillment asynchronously until a later time/event. The spirit of the proposal is that this special type of statement be a linear sequence of function executions (as opposed to nested function-reference callbacks delegating execution to other code). The special behavior is that in between each part/expression of the statement, evaluation of the statement itself (NOT the rest of the program) may be suspended until the previous part/expression is fulfilled. This would conceptually be like a yield/continuation localized to ONLY the statement in question, not affecting the linear execution of the rest of the program. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss I haven't found anyone else that has worked this out, and I have been keeping it kind of a secret, but seeing as I haven't yet done anything with it, I will reveal that what you propose is more or less possible with plain vanilla ecmascript 3. To modify your syntax proposal, what the syntax would look like is something like this: $(document).X(1,2).Y(3,4).Z(foo); this call returns an object, with a call, and an apply method (possibly a function object?) that when called, starts a chain of execution that is suspended at the finishing of each operand. Most of the time this suspension would be caused by a simple call to setTimeOut(next, 0); With other functions that are obviously asyncronous, such as XHR calls, the suspension is resumed at the point when the callback would normally be called. This would be made possible by a library, I will call MND for the purposes of this discussion. You start by passing MND an object with a set of related methods: var MyMonad = MND.make(MyObject); the MyMonad object has methods with all the same names as the object that you passed in, but when you call them, the names and arguments are simply placed on an internal stack, and an object with call/apply methods is returned. When the call function is invoked, it loops through the version of the stack stored on that particular object, by executing each method in turn, and in the spot where each method requires a callback, it places an additional helper function to continue execution of the stack. Additionally, the return value of the previous method call is passed in a parameter (perhaps as a property of this) to the next function to be executed. The initial function call (above, as $(document)), allows you to pass in some starting value for this chain of execution. The only drawback is that the call/apply method would itself require a callback function, for when the whole chain finishes, but that is still far preferable than multiply nested callbacks, which is, I presume, the problem you are attempting to solve. I think the syntax for this type of library is simple enough to not require new syntax. In fact it's pretty similar to jQuery, which as you probably know is quite popular specifically for its simplicity. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss