Re: function hoisting like var
It's not that your code is convoluted (although it is), it's that the added complexity to parse {{...}}, backwards incompatibility of that syntax (code generators), and the questionable aesthetics (it really is subjective) just make it infeasible. All just to provide a hoisted-let-like functionality. Plus, it's a dead horse that's been beaten one too many times :) I would like ES3.x to support let functionality, but I'd rather ES3.x just implement let statements/declarations, rather than {{...}}. I think others would agree with me here. I also prefer Igor's proposal more than {{...}}. And even if you solve problematic continuations (return/continue/break), I would like them to be generalized into first-class blocks. -Yuh-Ruey Chen On Wed, Aug 6, 2008 at 3:30 PM, Ingvar von Schoultz <[EMAIL PROTECTED]>wrote: > Yuh-Ruey Chen wrote: > >> FWIW, I definitely like this proposal more than any convoluted var-scoping >> block proposal. >> >> I just don't see the value of adding var-scoping blocks for the added >> parser complexity, and problematic return/break/continue. >> > > Unfortunately it seems people dislike the notation too much. > But the complexity that you discuss must be supported anyway. > Regardless whether it's written {let} or {{var}}, they both > say the same thing, and what they say is supported in ES4. > > My code looks convoluted only because it's an odd trick. > Not only does it add {let} functionality to ES3.1, it also > strives very hard to make the tiniest possible change. > > That tiny code is also conclusive proof that {{var}} is > extremely simple and has no capture problems, despite many > vague claims to the contrary. > > Unfortunately it seems people dislike the notation so much, > they prefer having no {let} functionality at all in ES3.1. > > -- > Ingvar von Schoultz > > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Yuh-Ruey Chen wrote: > FWIW, I definitely like this proposal more than any convoluted > var-scoping block proposal. > > I just don't see the value of adding var-scoping blocks for the added > parser complexity, and problematic return/break/continue. Unfortunately it seems people dislike the notation too much. But the complexity that you discuss must be supported anyway. Regardless whether it's written {let} or {{var}}, they both say the same thing, and what they say is supported in ES4. My code looks convoluted only because it's an odd trick. Not only does it add {let} functionality to ES3.1, it also strives very hard to make the tiniest possible change. That tiny code is also conclusive proof that {{var}} is extremely simple and has no capture problems, despite many vague claims to the contrary. Unfortunately it seems people dislike the notation so much, they prefer having no {let} functionality at all in ES3.1. -- Ingvar von Schoultz ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
FWIW, I definitely like this proposal more than any convoluted var-scoping block proposal. I just don't see the value of adding var-scoping blocks for the added parser complexity, and problematic return/break/continue. Even if the return/break/continue problem is solved, it shouldn't just be for var-scoping blocks - it should be generalized to first-class Ruby-esque block. So if we ever want to add var-scoping blocks with proper return/break/continue, consider Ruby-esque blocks. Something like: function treePreorder(tree, func) { func(tree.value); if (tree.left) treePreorder(tree.left, func); if (tree.right) treePreorder(tree.right, func); } function treeContains(tree, x) { treePreorder(some_tree, block(val) { if (val == x) return true; }); return false; } Though, I'd imagine implementing this would also be difficult (at the very least, non-trivial), and this example can be easily replaced with one that used exceptions/try/catch anyway. -Yuh-Ruey Igor Bukanov wrote: > 2008/7/28 Ingvar von Schoultz <[EMAIL PROTECTED]>: > > > > {{ }} is just the same as a scoping function used on ES3: > > > >(function() { code })() > > As Lars Hansen has pointed out any proposal for a shorthand for > (function() { code })() has to deal with break/continue/return inside > the code. This is the the reason if anything I would prefer in ES3.1 > just shorthands for function definitions like > > function() expr - equivalent to function () { return expr; }. This is > already in ES4 and is implemented by at least on implementation > (SpiderMonkey). > > or > > function optional_name { code } - equivalent to function > optional_name() { code } - a hypothetical shortcut that would allow to > write a pseudo-blocks like > > function { > }(); > > with clear emphasis that this is a lambda with usual rules for > break/continue/return. > > Regards, Igor > ___ > Es3.x-discuss mailing list > [EMAIL PROTECTED] > https://mail.mozilla.org/listinfo/es3.x-discuss > > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Okay then, even shorter. Brendan Eich wrote: > But it is not what you proposed. In what way? Please be more specific, because I don't know what this supposed proposal of mine is. For example, those scope questions mention rebinding in a visible scope, midway through its code block, but that's unrelated to anything I've proposed and unrelated to how JavaScript works. I've tried to guess what you think I've proposed from the scope questions, but the guessing has made my answers long. Stupid mistake, I should have asked instead, sorry. So please say something specific that I can address. > Waldemar wrote a while back: "Keep in mind that function assignments > hoist to the beginning of the scope in which the function is defined, > so your proposal won't work." It works perfectly well. The initial |undefined| is fully intentional, it protects against capture problems. It's a minor limitation, certainly not a showstopper. -- Ingvar von Schoultz ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Very brief! Brendan Eich wrote: > On Jul 26, 2008, at 2:07 PM, Ingvar von Schoultz wrote: > >> You can't get away from supporting this: >> >> { >> function a(){} >> var b = a; >> } >> >> ES4 is planning to support function declarations locally >> bound in blocks, so the above is valid ES4 code. >> >> What you see above is function b() hoisting like var. >> >> (I said b, not a.) > > What you said does not make sense. It's true that var b is hoisted to > the top of the program or function body. But it is not initialized > until control flows through the assignment b = a that is part of the > var declaration. So there is no capture problem. Of course not, that's exactly my point. I'm showing that hoisting can be done without capture problems, and largely re-using existing well-known functionality. b() is hoisted to the global scope, which means it's bound there and visible throughout. At the top it's |undefined|, to protect against capture problems in case the programmer inserts a local variable: { let c; function a(){} var b = a; } The function should become callable from just before we enter the local scope at the {. Calling becomes safe at this spot. >> There is no far-too-complicated split-scope complexity. There >> is no capturing of variables that haven't been declared yet. >> It's simple, intuitive, well-defined and well-behaved. > > Thanks, I agree. But it is not what you proposed. What is not what I proposed? In which proposal did I not propose it? > Again, from > Waldemar's original reply, but with your proposed {{}} interpolated > and the elided code amended to say what the consequence is: > > // outer scope > function c() ...; > > // inner scope > {{ >if (foo) { > const c = 37; >} >... c in your proposal must be hoisted to the {{, >so it can't be function c -- yet it can't be >initialized to 37 if foo is "falsy" ... > }} Since it's bound to {{ }}, it's visible and shadowing c() throughout {{ }}. It's |undefined| at the top. It may be assigned 37 under the if(). It should behave exactly as if you had declared it a var, with only one difference: Assigning a second time throws an error. > You could reply that const is new (sort of -- two browsers already > implement it one way, another treats it as var) and therefore should > always scope to { or {{, whichever is closer. But the point stands if > you replace const with function or var and hoist to the {{. What point? It's what the programmer coded. I can't find the problem. Please explain. > Repeating > the next counter-example, with {{}} changes again, to track your > proposal since the original exchange with Waldemar: > > // outer scope > function c() ...; > > // inner scope > {{ >function f() { > return c; >} >a = f(); >if (foo) { > const c = 37; >} >b = f(); >... just what do a and b hold here? Was f's captured >variable rebound by the if statement? ... > }} > > And so on. Since it's bound to {{ }}, it's visible and shadowing c() throughout {{ }}. It's |undefined| at the top. It may be assigned 37 under the if(). If you're allowed to read an unassigned const, |a| will be |undefined| and |b| will be either |undefined| or 37. You say rebinding. Why? I'd expect a simple assignment. Please explain. >> The above is the /exact/ functionality of function hoisting >> like var, apart from using two names. You can refuse the >> clearer syntax, but you can't refuse the above code and >> functionality. > > I think I see the confusion now. Do you believe that in the var b = > a; code you wrote, both the binding of the var named b *and* its > initialization with the value of the function object denoted a are > hoisted? Hoisted up to what point? The assignment stays where it's written. > Waldemar wrote a while back: "Keep in mind that function assignments > hoist to the beginning of the scope in which the function is defined, > so your proposal won't work." It's a minor limitation, not a showstopper, not even close. It doesn't mean that it "doesn't work". The arrangement is intentional, acceptable, easy to understand and very useful. The typical use case is if(). Then this behavior is exactly what you expect. > The word "assignment" where "definition" was perhaps more precise > (function definitions replace extant properties of the same name in > the variable object, they are not equivalent to assignment > expressions) may have misled you. From the context and the long- > standing spec and implementation behavior with functions not in > blocks or any other sub-statement position, it was clear (I think) > what was meant, but I can see how this could be confusing. > > Assignment expressions and initializers in var statements do not > hoist or otherwise move in the flow of control. I'm well aware of all this. -- Ingvar von Schoultz --- (M
Re: function hoisting like var
Thank you for your clear and to-the-point reply. I'll make a /much/ shorter response. For some reason I find brevity very difficult to attain. But I'll discipline and restrain my verbosity. Ingvar Brendan Eich wrote: > On Jul 30, 2008, at 3:13 PM, Ingvar von Schoultz wrote: > >> Regarding my explanations quoted below, did they clarify >> things? > > No, and I don't have time right now to deal with the great number of > words you have dedicated to promoting your ideas. This is a shame, > since you could have a point, but I simply can't expend the effort to > try to find it given other priorities. Sorry, this is not something > I'm happy about, but it's not entirely due to my being busy (i.e., > it's not just me -- it's you :-/). > > May I suggest using fewer words when replying than you have? > Generally proportionate responses would be best. I'm assuming fair > play, i.e., that people are not resorting to too short and dismissive > a style of replying. I'm not doing that here, I'm just letting you > know I don't have time to plow through what you have written. Maybe > someone else on the list has the time. > > /be > > ___ > Es4-discuss mailing list > Es4-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es4-discuss > -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
On Jul 30, 2008, at 3:13 PM, Ingvar von Schoultz wrote: > Regarding my explanations quoted below, did they clarify > things? No, and I don't have time right now to deal with the great number of words you have dedicated to promoting your ideas. This is a shame, since you could have a point, but I simply can't expend the effort to try to find it given other priorities. Sorry, this is not something I'm happy about, but it's not entirely due to my being busy (i.e., it's not just me -- it's you :-/). May I suggest using fewer words when replying than you have? Generally proportionate responses would be best. I'm assuming fair play, i.e., that people are not resorting to too short and dismissive a style of replying. I'm not doing that here, I'm just letting you know I don't have time to plow through what you have written. Maybe someone else on the list has the time. /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: A simple translation of the scoping-block syntax sugar -- Was: Re: function hoisting like var
Ingvar von Schoultz wrote: > Any variable > that you declare anywhere will simply splash out of any { } and > attach itself to the nearest surrounding {{ }}, becoming visible > in the entire space between them. Int this splashing out of { }, function declarations are a special case. Although implementations differ, I think {{ }} could serve as an opt-in where they become specified to follow clear rules. In my opinion the most useful rules would be: The name is visible in the entire space between the nearest surrounding {{ }}. Usually it's also callable in that entire space, but there are a few exceptions. If you put the declaration in a sequential construct, for example under if(), then at the {{ you can't call it (it's |undefined|), and it becomes callable only from the sequential construct and onward. If there is a { at the beginning of the sequential construct, the function becomes callable from the { and onward. If you make more than one declaration with the same name, this makes all the declarations of that name sequential. Then at {{ you can't call any of the versions of the function (again |undefined|). Each version becomes callable at the spot of declaration. In all other cases the function is callable in the entire space between {{ }}. (This is not intended as an exhaustively detailed description, just an overview.) (The rules will have to be changed a little if let declarations are allowed between {{ }}, or if allowing them there in a future version should be possible. And reserving the possibility might be a good idea -- who knows what people will want or will invent. To allow that, the rules become slightly more limiting.) -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Regarding my explanations quoted below, did they clarify things? It would be a relief to know that things are now clear and understandable, if they are. If there are still things that seem unclear, strange, incompatible or impractical, please ask about them! After some thinking I've found that I could have explained some of the things below better, making them clearer. Should I post better explanations? I'm really very curious about that rebinding problem! Both what it means, and where I seem to propose it (or actually propose it, inadvertently). Ingvar Ingvar von Schoultz wrote: > Sorry about the length of this, but I'm trying to cover the > unclear things, and often I don't know which things are unclear. > > Brendan Eich wrote: >> On Jul 26, 2008, at 2:07 PM, Ingvar von Schoultz wrote: >> >>> You can't get away from supporting this: >>> >>> { >>> function a(){} >>> var b = a; >>> } >>> >>> ES4 is planning to support function declarations locally >>> bound in blocks, so the above is valid ES4 code. >>> >>> What you see above is function b() hoisting like var. >>> >>> (I said b, not a.) >> What you said does not make sense. It's true that var b is hoisted to >> the top of the program or function body. But it is not initialized >> until control flows through the assignment b = a that is part of the >> var declaration. So there is no capture problem. > > That's my point! There isn't any capture problem. That's exactly > what I'm showing here. And, more importantly, you can't insert a > capture problem while keeping the structure intact. The arrangement > is inherently well-behaved. > > I'm trying to show that you can support functions that hoist like > var in a well-behaving way, and that this is /not/ complicated. > And the snippet is intended as proof. > > But perhaps I should interpret what you said somewhat differently. > > The snippet, as shown here, does not have a capture problem. > But if you "improve" the hoisting carelessly, there's a threat > of a capture problem lurking within it. (That's assuming that > I understand "capture problem" correctly -- this is a rare > case of Wikipedia not explaining a computing term.) > > Somebody might want to "improve" the hoisting by making it so > that the function is assigned (is callable) from before we enter > the global scope. > > Let's assume, for the argument, that the above code magically > starts to behave that way. Then it will work fine as long as it > stays the same. But later the programmer might decide to add a > local variable: > > { > function a(){} > var b = a; > let c = 3; > } > > c is now visible from inside a(), but exists only when we enter > the block. So in this situation a() must not be called before > we enter the block. The function must no longer be assigned > (callable) at the top of the global scope. > > I would consider it extremely surprising semantics if I can call > a() above the block, but only before I add that local variable, > and this suddenly changes just because I add c. It's a huge change, > it's far away, and it's unrelated. > > So for the sake of consistency and predictability we must assign > |undefined| whenever the code structure allows a capture problem > to be inserted as a side effect of doing something unrelated, > like adding |let c|. > > That's why I said this, in the email where I first showed this > snippet: > > ,--- > | Assigning |undefined| is correct for any function whose > | assignment depends on sequential code. The above is such a > | sequential dependency, even though it may not look that way. > `--- > > It may not look sequential, but that's just because I left out > a lot of details, in an attempt to keep it as brief as ever > possible, to minimize any misunderstandings. > > As you can see, in my opinion, what I'm saying does make perfect > sense! > > The claim that just because of this limitation my proposal > "doesn't work" is in my opinion quite mistaken. I consider > this functionality fully acceptable. It's simple, understandable > and predictable. Sure it's a limitation, but a minor one. It's > /far/ better and more useful and intuitive than having functions > not hoisting out at all. > > The usual use case will be an if() or some such. Then the > programmer fully expects the function to be available only > afterward. Very useful. Using it in a bare block like the > above will be unusual, but if used, the rules are simple. > >>> There is no far-too-complicated split-scope complexity. There >>> is no capturing of variables that haven't been declared yet. >>> It's simple, intuitive, well-defined and well-behaved. >> Thanks, I agree. But it is not what you proposed. > > Sorry, I don't understand. What is not what I proposed, and > in which one of my proposals did I not propose it? > >> Again, from >> Waldemar's original reply, but with your proposed {{}} interpolated >> and the elide
Re: A simple translation of the scoping-block syntax sugar -- Was: Re: function hoisting like var
The translation can be made simpler. First, define a unique value, to be returned when the end of the scoping block is reached. If done in JavaScript: var _EndOfBlock = {}; Then each {{ }} can be translated to this: var _ReturnValue = (function (arguments) { // Any governing for(), while() or switch() goes here. { // The code between {{ }} goes here. } return _EndOfBlock; }).call (this, arguments); if (_ReturnValue != _EndOfBlock) return _ReturnValue; Ingvar Ingvar von Schoultz wrote: > The simple translation of {{ }} that I posted yesterday needs > an improvement. It must pass |this| and |arguments| to the scoping > function. > > I still think it looks quite small and simple, and that it would > be a very useful addition to the language. > > try > { var _ReturnValue = (function (arguments) > { > // Any governing for(), while() or switch() goes here. > { > // The code between {{ }} goes here. > } > throw _NormalEndSignal; > }).call (this, arguments); > return _ReturnValue; > } > catch (_Sig) > { > if (_Sig != _NormalEndSignal) > throw _Sig; > } > > We must use .call(), not .apply(), so that we pass the arguments > object as such, with the outer function as arguments.callee. > > In the global scope, |arguments| will be undefined, unless the > programmer has defined it. It should remain undefined inside the > scoping function. > > As an alternative to the above parameter passing, I suppose the > implementation can simply remove the scope function's arguments > object, thereby making the outer arguments object visible. > > Initial underscore means hidden, invisible. > > For a description of the translation, see the quoted text below. > > Ingvar > > > > Ingvar von Schoultz wrote: >> Ingvar von Schoultz wrote: >>> In theory {{ code }} could be converted to a function that >>> returns information about whatever break/continue/return was >>> reached. >> I now think this could be made very simple. >> >> The solution is to make this version slightly limited. Don't >> support break/continue statements that mention any label >> outside {{ }}. Leave that for a future version. >> >> This simplifies things tremendously! And you don't need that >> kind of break/continue all that often. (But a future version >> must include it.) >> >> This limited solution only needs break/continue functionality >> that is already supported. Even the necessary label checking >> is already supported. An unsupported break such as the following >> gives a syntax error if you translate {{ }} to a one-shot >> function: >> >> Outer: >> for (var OutName in OutThing) >> for (var InName in InThing) >> {{ >> break Outer; >> }} >> >> The error message that I get says "undefined label", which >> is misleading, but apart from that it works perfectly. >> >> If people find the above limited support for break/continue >> acceptable for this version, all that remains is the return >> statement. >> >> It seems easiest to use a solution that leaves all the return >> statements in the original code intact. This makes the translation >> from {{ }} to function a little elaborate and odd, but everything >> is nicely contained at one spot. >> >> Within the created function, if control reaches the final }}, >> throw a special error that isn't really an error, rather the >> opposite, it's a signal that indicates that this is a normal >> termination. When this signal is received, continue below }}. >> >> If instead, within the created function, control reaches a >> return statement that appears in the original code, the result >> is a regular return, without the above thrown signal. This >> indicates that whatever value was returned should be passed >> along as return value of the enclosing function. >> >> This means that {{ }} is essentially translated into this: >> >> try >> { var ReturnValue = (function() >> { // The code that was written between {{ }} goes here. >> throw NormalEndSignal; >> })(); >> return ReturnValue; >> } >> catch (Sig) >> { if (Sig != NormalEndSignal) >> throw Sig; >> } >> >> It seems to me that this becomes very nicely contained, >> very manageable. >> >> Implementations will probably want to optimize away this >> entire elaborate arrangement and replace it with plain and >> simple scoping blocks. But they can take their time. The >> above provides the functionality in a simple way. >> >> That is, unless I've missed something, and the above solution >> doesn't work the way I think it does. >> > -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and u
Re: A simple translation of the scoping-block syntax sugar -- Was: Re: function hoisting like var
I'd like to summarize some clarifications and arguments. I'm thinking of what it might be like if {{ }} should become available in ES3.1. === Intuitive === The proposed {{ }} mean exactly the same thing as { } in C, Java etc. If switching between languages causes you any difficulties, simply use {{ }} everywhere in your ES3.1 code. This way you get the braces that you're used to from C and Java, apart from a slightly different notation. Think of it as JavaScript having a small difference in brace notation while the functionality is the same. === Control flow === In ES3 you can use { } for plain control flow, without any scoping. This is very useful for small projects. If this is not a good fit for your projects, it's still very useful elsewhere. Please don't deprecate this functionality. For more on the usefulness of this plain control flow, see: https://mail.mozilla.org/pipermail/es4-discuss/2008-July/003353.html === Difference === If you want the full flexibility of using both {{ }} and { }, first decide which type of brace you want to use most in your program. Stick with that almost everywhere. Make an exception only when you have a clear and specific reason, because you need the functionality of the other type. This way your code will be consistent and readable. You can view the {{ }} as containers for variables. Any variable that you declare anywhere will simply splash out of any { } and attach itself to the nearest surrounding {{ }}, becoming visible in the entire space between them. If you prefer a more low-level view, { } are plain jumps and branches, and only {{ }} affect the scope chain. === Ugly === The proposed {{ }} will inevitably look horrible in emails if you use a proportional font such as Times New Roman. Real code is never displayed in such a font. Try a programmer's editor with a suitable font and syntax coloring. It looks completely different! If people still find it ugly, I hope a good alternative can be found, because the functionality would be very useful. === Let declarations === There are existing implementations that support let. My proposal is that /let declarations/ should be completely disabled between {{ }}. This of course includes all { } that are nested between {{ }}. The only reason is simplicity, mainly for the script programmer. Outside {{ }} they should be enabled, for compatibility and to satisfy those who prefer the let and var combination. -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: A simple translation of the scoping-block syntax sugar -- Was: Re: function hoisting like var
If the simple translation of {{ }} is used, any governing for(), while() or switch() must be moved inside the scoping function. A very simple, very minimalistic approach may be enough. for (var Name in Thing) {{ }} Name is locally contained inside {{ }} while Thing is outside. But maybe the compiler doesn't have to make this distinction. Personally I'd never use the same name with different meanings so close together, like this: var Thing = ...; for (var Name in Thing) {{ var Thing = ...; }} I find that obscure and error-prone. If the limitation is acceptable, a very minimalistic translation of {{ }} could simply move the entire for (...) inside the scoping function, and leave it at that. As long as Thing isn't redeclared inside, the outer Thing is visible and it works. Does this make it simple enough for ES3.1? As an added bonus, the functionality becomes very easy to explain. The rules become very plain and simple. I don't know if a let statement with this limitation would be useful. Every description of let that I can find re-uses names. But if it's useful, it could be trivially implemented as syntax sugar: let (a = x, b = y) {{ }} would be syntax sugar for {{ var a = x, b = y; }} However "let" has different semantics in at least one existing implementation (it does distinguish between same-name variables in the two scopes), so if a minimalistic let is introduced, it should probably use a different keyword. -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
A simple translation of the scoping-block syntax sugar -- Was: Re: function hoisting like var
The simple translation of {{ }} that I posted yesterday needs an improvement. It must pass |this| and |arguments| to the scoping function. I still think it looks quite small and simple, and that it would be a very useful addition to the language. try { var _ReturnValue = (function (arguments) { // Any governing for(), while() or switch() goes here. { // The code between {{ }} goes here. } throw _NormalEndSignal; }).call (this, arguments); return _ReturnValue; } catch (_Sig) { if (_Sig != _NormalEndSignal) throw _Sig; } We must use .call(), not .apply(), so that we pass the arguments object as such, with the outer function as arguments.callee. In the global scope, |arguments| will be undefined, unless the programmer has defined it. It should remain undefined inside the scoping function. As an alternative to the above parameter passing, I suppose the implementation can simply remove the scope function's arguments object, thereby making the outer arguments object visible. Initial underscore means hidden, invisible. For a description of the translation, see the quoted text below. Ingvar Ingvar von Schoultz wrote: > Ingvar von Schoultz wrote: >> In theory {{ code }} could be converted to a function that >> returns information about whatever break/continue/return was >> reached. > > I now think this could be made very simple. > > The solution is to make this version slightly limited. Don't > support break/continue statements that mention any label > outside {{ }}. Leave that for a future version. > > This simplifies things tremendously! And you don't need that > kind of break/continue all that often. (But a future version > must include it.) > > This limited solution only needs break/continue functionality > that is already supported. Even the necessary label checking > is already supported. An unsupported break such as the following > gives a syntax error if you translate {{ }} to a one-shot > function: > > Outer: > for (var OutName in OutThing) > for (var InName in InThing) > {{ > break Outer; > }} > > The error message that I get says "undefined label", which > is misleading, but apart from that it works perfectly. > > If people find the above limited support for break/continue > acceptable for this version, all that remains is the return > statement. > > It seems easiest to use a solution that leaves all the return > statements in the original code intact. This makes the translation > from {{ }} to function a little elaborate and odd, but everything > is nicely contained at one spot. > > Within the created function, if control reaches the final }}, > throw a special error that isn't really an error, rather the > opposite, it's a signal that indicates that this is a normal > termination. When this signal is received, continue below }}. > > If instead, within the created function, control reaches a > return statement that appears in the original code, the result > is a regular return, without the above thrown signal. This > indicates that whatever value was returned should be passed > along as return value of the enclosing function. > > This means that {{ }} is essentially translated into this: > > try > { var ReturnValue = (function() > { // The code that was written between {{ }} goes here. > throw NormalEndSignal; > })(); > return ReturnValue; > } > catch (Sig) > { if (Sig != NormalEndSignal) > throw Sig; > } > > It seems to me that this becomes very nicely contained, > very manageable. > > Implementations will probably want to optimize away this > entire elaborate arrangement and replace it with plain and > simple scoping blocks. But they can take their time. The > above provides the functionality in a simple way. > > That is, unless I've missed something, and the above solution > doesn't work the way I think it does. > -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Ingvar von Schoultz wrote: > In theory {{ code }} could be converted to a function that > returns information about whatever break/continue/return was > reached. But I'd be quite surprised if that is easy. > > Something like this. Written with syntax sugar: > > Outer: > for (var OutName in OutThing) > for (var InName in InThing) > {{ > break Outer; > }} > > Translation: > > Outer: > for (var OutName in OutThing) > { > var _Result = (function (_InThing) > { > for (var InName in _InThing) > { > return ({JumpSpot: 'break Outer'}) > } > })(InThing); > if (_Result.JumpSpot == 'break Outer') > break Outer; > } > > The inner for() is part of the scoping block, so it belongs > inside, even though the original code has it above. > > We must make sure the value of InThing is available inside > even if the name is declared for a different variable inside. > > I use initial underscore to indicate something internal and > invisible. > > It doesn't look complicated here! Unfortunately these things > have a terrible tendency to grow in complexity... I now think this could be made very simple. The solution is to make this version slightly limited. Don't support break/continue statements that mention any label outside {{ }}. Leave that for a future version. This simplifies things tremendously! And you don't need that kind of break/continue all that often. (But a future version must include it.) This limited solution only needs break/continue functionality that is already supported. Even the necessary label checking is already supported. An unsupported break such as the following gives a syntax error if you translate {{ }} to a one-shot function: Outer: for (var OutName in OutThing) for (var InName in InThing) {{ break Outer; }} The error message that I get says "undefined label", which is misleading, but apart from that it works perfectly. If people find the above limited support for break/continue acceptable for this version, all that remains is the return statement. It seems easiest to use a solution that leaves all the return statements in the original code intact. This makes the translation from {{ }} to function a little elaborate and odd, but everything is nicely contained at one spot. Within the created function, if control reaches the final }}, throw a special error that isn't really an error, rather the opposite, it's a signal that indicates that this is a normal termination. When this signal is received, continue below }}. If instead, within the created function, control reaches a return statement that appears in the original code, the result is a regular return, without the above thrown signal. This indicates that whatever value was returned should be passed along as return value of the enclosing function. This means that {{ }} is essentially translated into this: try { var ReturnValue = (function() { // The code that was written between {{ }} goes here. throw NormalEndSignal; })(); return ReturnValue; } catch (Sig) { if (Sig != NormalEndSignal) throw Sig; } It seems to me that this becomes very nicely contained, very manageable. Implementations will probably want to optimize away this entire elaborate arrangement and replace it with plain and simple scoping blocks. But they can take their time. The above provides the functionality in a simple way. That is, unless I've missed something, and the above solution doesn't work the way I think it does. -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Michael Haufe wrote: > Instead of all this fluff about a better block, regardless of its syntax > shape .wouldn't it be better to deprecate "var" for "let" and adjust > the scoping rules accordingly? Deprecate var? No! Please, no! JavaScript's scoping rules are useful! They mustn't be scrapped just because other languages have inferior rules! JavaScript lets you group assignments in useful ways. As when you want debugging and regular mode: if (Debugging) { var DatabaseName = "TestDatabase"; var DisplayCount = 5; } else { var DatabaseName = "RealDatabase"; var DisplayCount = 15; } (Using |var| twice for the same variable as above is simply redundant, it means the same thing as using it only once.) With inferior languages this is much more awkward: let DatabaseName; let DisplayCount; if (Debugging) { DatabaseName = "TestDatabase"; DisplayCount = 5; } else { DatabaseName = "RealDatabase"; DisplayCount = 15; } If you have ten variables you get thirty lines to keep track of, ten of them uselessly redundant. That's okay for a big project, where that kind of discipline is helpful, but for very small programs it's just awkward and messy. And what if they are constants? Separating a const declaration from its assignment is weird, I prefer not to. But the alternative would be this: if (Debugging) const DatabaseName = "TestDatabase"; else const DatabaseName = "RealDatabase"; if (Debugging) const DisplayCount = 5; else const DisplayCount = 15; Imagine that with ten settings! It's just plain unstructured and messy! And that's assuming they don't scrap that possibility too, along with var. The /only/ drawback in JavaScript's scoping is that scoping is limited to function blocks. That's a major drawback -- it's /seriously/ annoying -- but that's no reason for scrapping something so elegant and useful! Just add what's missing, but keep also the thing that's so beautifully superior. > I would think this would be an easier > progression for the developer Here's how you can switch between languages in a really simple and intuitive way: In JavaScript, always type {{ }}, never type { }. Then the only thing you have to remember is that for JavaScript code you use this special bracing. That's all. Then some day in the future, when you're used to the above, you'll encounter a situation where you want to group assignments, as in my debugging-mode example. So you'll start using { } occasionally. Before you know it, you'll bless the ability to use this construct whenever you want it. Then you'll have no difficulty navigating the two, because you'll be used to them, they'll feel ordinary. They'll feel intuitive! Then the only problem is that when you use other languages you'll sigh, longing for the flexibility of JavaScript. > and easier to implement For the implementation, having a simultaneous mix of var and let is /much/ more complex than having just a single scoping construct. If there wasn't any let, only var and {{ }}, things would become very simple indeed. Then { and } would be reduced to plain and simple gotos, with a few ifs and such thrown in. Meanwhile {{ and }} would become the single consistent holder of all scoping functionality. There wouldn't be any hoisting to an outer scope. Everything would always attach to the nearest {{ }}. There would be no complexity related to the two constructs "block" and "variable object", you'd have only one of them, always represented by {{ }}. A single scope construct and plain goto. Much simpler. > instead of > throwing in redundant syntax that isn't necessarily intuitive as is > shown by the examples thus far. I don't agree that it's redundant syntax. That one-shot function is a highly awkward and kludgey construct that people use only because there is no other way to do it. The functionality is necessary, so you are forced to use it, but if it weren't so necessary you wouldn't use that kludge. > (especially for experienced developers > with bad habits from other languages). How are we real javascripters to defend our wonderfully superior language against their ruthless onslaught? -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Brendan Eich wrote: > On Jul 26, 2008, at 2:06 PM, Ingvar von Schoultz wrote: > >> How sad! It seemed such a simple and intuitive notation! > > Opinions vary, but all the ones I heard at the Ecma TC39 meeting > found it neither simple nor intuitive, and some abhorred it on > aesthetic grounds to boot. Maybe one reason people find {{ }} ugly is that they read these emails in a proportional font, for example Times New Roman. In such fonts the braces are often oversized and weird, and just don't fit in. But real code is never read using such fonts! With a regular syntax-coloring editor, adjusted for JavaScript, using a font suitable for programming, it looks very different! -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Igor Bukanov wrote: > 2008/7/28 Ingvar von Schoultz <[EMAIL PROTECTED]>: >> {{ }} is just the same as a scoping function used on ES3: >> >>(function() { code })() > > As Lars Hansen has pointed out any proposal for a shorthand for > (function() { code })() has to deal with break/continue/return inside > the code. Indeed I wasn't thinking of that in my description. > This is the the reason if anything I would prefer in ES3.1 > just shorthands for function definitions like > > function() expr - equivalent to function () { return expr; }. This is > already in ES4 and is implemented by at least on implementation > (SpiderMonkey). I rarely feel a need for such tiny scoping blocks, but often long for big scoping blocks with intuitive syntax. > function optional_name { code } - equivalent to function > optional_name() { code } - a hypothetical shortcut that would allow to > write a pseudo-blocks like > > function { > }(); > > with clear emphasis that this is a lambda with usual rules for > break/continue/return. Yes, we can't have syntax that looks like a block but forbids or misunderstands break/continue/return. In theory {{ code }} could be converted to a function that returns information about whatever break/continue/return was reached. But I'd be quite surprised if that is easy. Something like this. Written with syntax sugar: Outer: for (var OutName in OutThing) for (var InName in InThing) {{ break Outer; }} Translation: Outer: for (var OutName in OutThing) { var _Result = (function (_InThing) { for (var InName in _InThing) { return ({JumpSpot: 'break Outer'}) } })(InThing); if (_Result.JumpSpot == 'break Outer') break Outer; } The inner for() is part of the scoping block, so it belongs inside, even though the original code has it above. We must make sure the value of InThing is available inside even if the name is declared for a different variable inside. I use initial underscore to indicate something internal and invisible. It doesn't look complicated here! Unfortunately these things have a terrible tendency to grow in complexity... -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Richard Cornford wrote: > Ingvar von Schoultz wrote: >> Richard Cornford wrote: > >>> { >>>1,2,3,4,5 >>> } >>> >>> - is a valid ES 3 Program (even if a pointless one); A Block >>> statement containing an Expression statement (with automatic >>> semi-colon insertion making the Expression statement >>> into - 1,2,3,4,5; -). >>> >>> eval('{1,2,3,4,5}') - results in the value 5, while - >>> eval('[1,2,3,4,5]') - returns a 5 element array. >> Yes. And if the rules for "{" remain unchanged, and "[" starts >> out assuming it's a literal, you get the same result with my rules. > > And if I wanted that block scope this - > > eval("{[\n eval('var a = 1'),eval('var b = 2'),eval('a + b')\n]}"); > > - will still give me an array (and side effects in the containing scope)? Goodness, if the code generator writes that, it deserves to melt! I'd say if you're aware of scoping blocks, and want to have a scoping block, and despite this insist on separating with commas rather than semicolons or bare newlines, well, then you deserve the array that you get! So the solution is to use semicolon or newline as separator, preferably somewhere near the beginning. Of course the real solution to all this is to use my original {{ }} instead. You get used to them. And they're very easy to type! -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Ingvar von Schoultz wrote: > Richard Cornford wrote: >> { >>1,2,3,4,5 >> } >> >> - is a valid ES 3 Program (even if a pointless one); A Block >> statement containing an Expression statement (with automatic >> semi-colon insertion making the Expression statement >> into - 1,2,3,4,5; -). >> >> eval('{1,2,3,4,5}') - results in the value 5, while - >> eval('[1,2,3,4,5]') - returns a 5 element array. > > Yes. And if the rules for "{" remain unchanged, and "[" starts > out assuming it's a literal, you get the same result with my rules. And if I wanted that block scope this - eval("{[\n eval('var a = 1'),eval('var b = 2'),eval('a + b')\n]}"); - will still give me an array (and side effects in the containing scope)? ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Mike Shaver wrote: > On Sun, Jul 27, 2008 at 9:15 PM, Ingvar von Schoultz > <[EMAIL PROTECTED]> wrote: >> Does it matter whether it's interpreted as an empty block or >> an empty discarded array? > > It's not always discarded: > > js> var x = 1 > js> eval ("if (x) [1, 2, 3]") > 1,2,3 That becomes an array, no problem. My "Does it matter" was about empty blocks only, in reply to your question: >> Are you saying that a block then may never be empty as a syntax >> rule? > Does it matter whether it's interpreted as an empty block or > an empty discarded array? Array is the default. An empty block gets misinterpreted as an empty array. So a code generator that produces an eval that returns a scoping block must deal with the special case that the block may be empty or contain a comma-separated list of values. It's the generator's own fault for producing such silly code, so I don't feel sorry for that generator. :-) -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
On Sun, Jul 27, 2008 at 9:15 PM, Ingvar von Schoultz <[EMAIL PROTECTED]> wrote: > Does it matter whether it's interpreted as an empty block or > an empty discarded array? It's not always discarded: js> var x = 1 js> eval ("if (x) [1, 2, 3]") 1,2,3 Mike ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Richard Cornford wrote: > Ingvar von Schoultz wrote: >> Igor Bukanov wrote: >>> 2008/7/28 Ingvar von Schoultz wrote: > > Any of this can be a valid ES3 code as [] always means an > array literal. I get the impression that disambiguation would be easy. >>> eval('[]') is a valid and, in fact, useful ES3 code. Similarly >>> eval('{[]}'). >> Yes, and by my rules they both create and return a new, empty >> array, which is intuitively expected and compatible. > > Are you saying that a block then may never be empty as a syntax > rule? ES 3 blocks are allowed to be empty and I bet there are > examples where blocks contain nothing but an IE/JScript > conditional comment and so are going to be interpreted as > being empty by other ES 3 implementations. (Comments are > allowed inside array literal definitions at present). Does it matter whether it's interpreted as an empty block or an empty discarded array? >> When I said that an array is a comma-separated list of values, >> the fact that I left out the empty and the single-value cases >> didn't mean that they should be seen as blocks! I just didn't >> want to write a lengthy, exhaustive full grammar... > > > { >1,2,3,4,5 > } > > - is a valid ES 3 Program (even if a pointless one); A Block > statement containing an Expression statement (with automatic > semi-colon insertion making the Expression statement > into - 1,2,3,4,5; -). > > eval('{1,2,3,4,5}') - results in the value 5, while - > eval('[1,2,3,4,5]') - returns a 5 element array. Yes. And if the rules for "{" remain unchanged, and "[" starts out assuming it's a literal, you get the same result with my rules. -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Igor Bukanov wrote: > 2008/7/28 Ingvar von Schoultz <[EMAIL PROTECTED]>: >> If [...] is preceded by =, or enclosed in ( ), or in some other >> position where you can't have a block, it's a literal. If it's >> a literal it must contain a comma-separated list of values, so >> if the syntax doesn't match this, it's a block. > > Such rules require an arbitrary look ahead in the parser so it can > distinguish that in cases like > > if (x) [arbitrary_expression;] > > [] means a block while in > > if (x) [arbitrarily_expression]; > > [] would mean a literal. > > This would require a mayor change in most if not all current ES parser > implementations. There were some proposals for ES4 syntax that would > require such look ahead, but they were rejected not only technical > grounds but also on the grounds that such look ahead poses > comprehension problem for a human brain! And here are we talking about > a minimalistic sugar for ES3.1. > > Regards, Igor > ___ > Es3.x-discuss mailing list > [EMAIL PROTECTED] > https://mail.mozilla.org/listinfo/es3.x-discuss > I wasn't aware that backtracking was a difficulty. That makes quite a difference! In theory this could be overcome. Often the ambiguity doesn't matter: if (x) [a(), b(), c()]; Block or throwaway array, the end result is the same. So in principle you could start out building an array, and on the first nonmatching syntax you discard the half-built array and build a scope block instead: if (x) [a(), b(), c(), d(), e(), let f = g;] Of course in practice such a solution is too messy, unless you have some extremely thorny problem that just can't be solved in any other way. And this certainly isn't that kind of problem. So [ ] are out. Unless they're reincarnated as: [: code :] Ah, now I know! I have the perfect solution, guaranteed to be unambiguous. Happy code! (-: Scoping blocks are delimited by smileys! :-) -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Ingvar von Schoultz wrote: > Igor Bukanov wrote: >> 2008/7/28 Ingvar von Schoultz wrote: Any of this can be a valid ES3 code as [] always means an array literal. >>> I get the impression that disambiguation would be easy. >> >> eval('[]') is a valid and, in fact, useful ES3 code. Similarly >> eval('{[]}'). > > Yes, and by my rules they both create and return a new, empty > array, which is intuitively expected and compatible. Are you saying that a block then may never be empty as a syntax rule? ES 3 blocks are allowed to be empty and I bet there are examples where blocks contain nothing but an IE/JScript conditional comment and so are going to be interpreted as being empty by other ES 3 implementations. (Comments are allowed inside array literal definitions at present). > When I said that an array is a comma-separated list of values, > the fact that I left out the empty and the single-value cases > didn't mean that they should be seen as blocks! I just didn't > want to write a lengthy, exhaustive full grammar... { 1,2,3,4,5 } - is a valid ES 3 Program (even if a pointless one); A Block statement containing an Expression statement (with automatic semi-colon insertion making the Expression statement into - 1,2,3,4,5; -). eval('{1,2,3,4,5}') - results in the value 5, while - eval('[1,2,3,4,5]') - returns a 5 element array. ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Mike Shaver wrote: > On Sun, Jul 27, 2008 at 7:51 PM, Ingvar von Schoultz > <[EMAIL PROTECTED]> wrote: >> >> Igor Bukanov wrote: >>> eval('[]') is a valid and, in fact, useful ES3 code. Similarly eval('{[]}'). >> Yes, and by my rules they both create and return a new, empty >> array, which is intuitively expected and compatible. > > And the latter only does because the { is parsed as starting a block; > if it were to start out assuming a literal, you would get an illegal > object initializer. I meant that "[" would follow those rules, not "{". The rules I sketched are definitely not usable for "{". >> I get the impression that the parser always must start out >> assuming it's a literal, and backtrack if the syntax doesn't >> fit. The only exception would be at a spot where a literal >> isn't possible while a block is possible, but I don't think >> any such spot is possible. > > if { block; } > > would seem to be such a spot, no? These are valid literals (immediately discarded, but valid syntax): if (true) [10, 20]; if (true) { [10, 20] }; Likewise valid: if (true) 10; > Regardless, I'm pretty sure ES3 > compat requires that a statement starting with a { be taken as a block > and not a literal, with no backtracking. > > js> {a:5, b:6} > typein:4: SyntaxError: invalid label: > typein:4: {a:5, b:6} > typein:4: ..^ > > Mike > ___ > Es4-discuss mailing list > Es4-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es4-discuss > -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
2008/7/28 Ingvar von Schoultz <[EMAIL PROTECTED]>: > If [...] is preceded by =, or enclosed in ( ), or in some other > position where you can't have a block, it's a literal. If it's > a literal it must contain a comma-separated list of values, so > if the syntax doesn't match this, it's a block. Such rules require an arbitrary look ahead in the parser so it can distinguish that in cases like if (x) [arbitrary_expression;] [] means a block while in if (x) [arbitrarily_expression]; [] would mean a literal. This would require a mayor change in most if not all current ES parser implementations. There were some proposals for ES4 syntax that would require such look ahead, but they were rejected not only technical grounds but also on the grounds that such look ahead poses comprehension problem for a human brain! And here are we talking about a minimalistic sugar for ES3.1. Regards, Igor ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
On Sun, Jul 27, 2008 at 7:51 PM, Ingvar von Schoultz <[EMAIL PROTECTED]> wrote: > > > Igor Bukanov wrote: >> eval('[]') is a valid and, in fact, useful ES3 code. Similarly eval('{[]}'). > > Yes, and by my rules they both create and return a new, empty > array, which is intuitively expected and compatible. And the latter only does because the { is parsed as starting a block; if it were to start out assuming a literal, you would get an illegal object initializer. > I get the impression that the parser always must start out > assuming it's a literal, and backtrack if the syntax doesn't > fit. The only exception would be at a spot where a literal > isn't possible while a block is possible, but I don't think > any such spot is possible. if { block; } would seem to be such a spot, no? Regardless, I'm pretty sure ES3 compat requires that a statement starting with a { be taken as a block and not a literal, with no backtracking. js> {a:5, b:6} typein:4: SyntaxError: invalid label: typein:4: {a:5, b:6} typein:4: ..^ Mike ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Igor Bukanov wrote: > 2008/7/28 Ingvar von Schoultz <[EMAIL PROTECTED]>: >> I wonder if people would like using them. > > Anything that is available in a browser will be used and abused ;). Wonderful! My notation will become popular! :-D >>> Any of this can be a valid ES3 code as [] always means an array literal. >> I get the impression that disambiguation would be easy. > > eval('[]') is a valid and, in fact, useful ES3 code. Similarly eval('{[]}'). Yes, and by my rules they both create and return a new, empty array, which is intuitively expected and compatible. When I said that an array is a comma-separated list of values, the fact that I left out the empty and the single-value cases didn't mean that they should be seen as blocks! I just didn't want to write a lengthy, exhaustive full grammar... I get the impression that the parser always must start out assuming it's a literal, and backtrack if the syntax doesn't fit. The only exception would be at a spot where a literal isn't possible while a block is possible, but I don't think any such spot is possible. -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
2008/7/28 Ingvar von Schoultz <[EMAIL PROTECTED]>: > > {{ }} is just the same as a scoping function used on ES3: > >(function() { code })() As Lars Hansen has pointed out any proposal for a shorthand for (function() { code })() has to deal with break/continue/return inside the code. This is the the reason if anything I would prefer in ES3.1 just shorthands for function definitions like function() expr - equivalent to function () { return expr; }. This is already in ES4 and is implemented by at least on implementation (SpiderMonkey). or function optional_name { code } - equivalent to function optional_name() { code } - a hypothetical shortcut that would allow to write a pseudo-blocks like function { }(); with clear emphasis that this is a lambda with usual rules for break/continue/return. Regards, Igor ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
2008/7/28 Ingvar von Schoultz <[EMAIL PROTECTED]>: > I wonder if people would like using them. Anything that is available in a browser will be used and abused ;). > >>> {[ code ]} >>> >>> [[ code ]] >>> >>> [ code ] >> >> Any of this can be a valid ES3 code as [] always means an array literal. > > I get the impression that disambiguation would be easy. eval('[]') is a valid and, in fact, useful ES3 code. Similarly eval('{[]}'). Regards, Igor ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Brendan Eich wrote: > On Jul 26, 2008, at 2:06 PM, Ingvar von Schoultz wrote: > >> How sad! It seemed such a simple and intuitive notation! > > Opinions vary, but all the ones I heard at the Ecma TC39 meeting > found it neither simple nor intuitive, and some abhorred it on > aesthetic grounds to boot. Not simple? How is that possible? There have been several misunderstandings. Did they spread that far? {{ }} is just the same as a scoping function used on ES3: (function() { code })() Everything works just the way I meant if you take ES3, or any platform that does /not/ support let declarations, and make it so that {{ }} becomes syntax sugar for the above one-shot scoping function. Of course, the way I think about {{ }}, I don't see it as a function, I see it as a name-binding scope. But the scoping effect is just that. For me, having a single scoping block is simpler than having two, and having a single visibility keyword is simpler than having two. And I think my notation is /much/ simpler than the one-shot function! {{ code }} (function() { code })() I do find my notation slightly ugly. But the one-shot function is worse in my view. Charming but very kludgey. (Thanks Igor for noticing that {{ }} are synonymous with one-shot scoping functions. Why didn't I think of that!) >> I think all of these would be unambiguous: >> >> {. code .} >> >> {: code :} >> >> {| code |} >> >> {[ code ]} >> >> [[ code ]] >> >> [ code ] > > These are either syntax errors without opt-in versioning, Yes, and this should guarantee that they are unique. I now have the impression that, on the client side, opt-in by version would be necessary in any case, with any notation. If old platforms accept the syntax, it changes existing semantics; if they don't, it requires opt-in to avoid errors. > or (the > last three) do create incompatible ambiguity (consider array > initialisers). It seems to me that they could be disambiguated easily. I comment on this in a reply to Igor. > What's more, as Waldemar pointed out many threads (and too many > words) ago, they create capture problems. There were misunderstandings. If there are fundamental differences in this regard between {{ }} and one-shot scoping functions, I can't find them. > Please work through the > last mail I sent before replying; if some vocabulary or infelicitous > word choice is causing any confusion, feel free to mail me privately > and ask pointed questions. Thanks, Thanks for the invitation. I'll certainly take you up on it if the need or urge arises. -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Igor Bukanov wrote: > 2008/7/26 Ingvar von Schoultz <[EMAIL PROTECTED]>: > >> I think all of these would be unambiguous: >> >>{. code .} > > {. not work since {.0; } is a valid ES3 Oops! True indeed. >>{: code :} >> >>{| code |} > > These 2 cases are indeed invalid ES3. I wonder if people would like using them. >>{[ code ]} >> >>[[ code ]] >> >>[ code ] > > Any of this can be a valid ES3 code as [] always means an array literal. I get the impression that disambiguation would be easy. If [...] is preceded by =, or enclosed in ( ), or in some other position where you can't have a block, it's a literal. If it's a literal it must contain a comma-separated list of values, so if the syntax doesn't match this, it's a block. These two rules should provide very early disambiguation in almost all cases. As a last resort, consider that the whole point of a scoping block is that you declare some names local within it. I don't think you can write text that looks like such a declaration in an array literal. (But I'm not yet sure about the ES4 syntax.) So I think a final disambiguation rule could say that it's a literal if the syntax inside matches a literal. Checking a few cases, this seemed to work fine, so I felt that just as {...} can be used both for literals and blocks, probably [...] can be used too. But my analysis was superficial. A thorough analysis becomes interesting only if one of these becomes popular. -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Sorry about the length of this, but I'm trying to cover the unclear things, and often I don't know which things are unclear. Brendan Eich wrote: > On Jul 26, 2008, at 2:07 PM, Ingvar von Schoultz wrote: > >> You can't get away from supporting this: >> >> { >> function a(){} >> var b = a; >> } >> >> ES4 is planning to support function declarations locally >> bound in blocks, so the above is valid ES4 code. >> >> What you see above is function b() hoisting like var. >> >> (I said b, not a.) > > What you said does not make sense. It's true that var b is hoisted to > the top of the program or function body. But it is not initialized > until control flows through the assignment b = a that is part of the > var declaration. So there is no capture problem. That's my point! There isn't any capture problem. That's exactly what I'm showing here. And, more importantly, you can't insert a capture problem while keeping the structure intact. The arrangement is inherently well-behaved. I'm trying to show that you can support functions that hoist like var in a well-behaving way, and that this is /not/ complicated. And the snippet is intended as proof. But perhaps I should interpret what you said somewhat differently. The snippet, as shown here, does not have a capture problem. But if you "improve" the hoisting carelessly, there's a threat of a capture problem lurking within it. (That's assuming that I understand "capture problem" correctly -- this is a rare case of Wikipedia not explaining a computing term.) Somebody might want to "improve" the hoisting by making it so that the function is assigned (is callable) from before we enter the global scope. Let's assume, for the argument, that the above code magically starts to behave that way. Then it will work fine as long as it stays the same. But later the programmer might decide to add a local variable: { function a(){} var b = a; let c = 3; } c is now visible from inside a(), but exists only when we enter the block. So in this situation a() must not be called before we enter the block. The function must no longer be assigned (callable) at the top of the global scope. I would consider it extremely surprising semantics if I can call a() above the block, but only before I add that local variable, and this suddenly changes just because I add c. It's a huge change, it's far away, and it's unrelated. So for the sake of consistency and predictability we must assign |undefined| whenever the code structure allows a capture problem to be inserted as a side effect of doing something unrelated, like adding |let c|. That's why I said this, in the email where I first showed this snippet: ,--- | Assigning |undefined| is correct for any function whose | assignment depends on sequential code. The above is such a | sequential dependency, even though it may not look that way. `--- It may not look sequential, but that's just because I left out a lot of details, in an attempt to keep it as brief as ever possible, to minimize any misunderstandings. As you can see, in my opinion, what I'm saying does make perfect sense! The claim that just because of this limitation my proposal "doesn't work" is in my opinion quite mistaken. I consider this functionality fully acceptable. It's simple, understandable and predictable. Sure it's a limitation, but a minor one. It's /far/ better and more useful and intuitive than having functions not hoisting out at all. The usual use case will be an if() or some such. Then the programmer fully expects the function to be available only afterward. Very useful. Using it in a bare block like the above will be unusual, but if used, the rules are simple. >> There is no far-too-complicated split-scope complexity. There >> is no capturing of variables that haven't been declared yet. >> It's simple, intuitive, well-defined and well-behaved. > > Thanks, I agree. But it is not what you proposed. Sorry, I don't understand. What is not what I proposed, and in which one of my proposals did I not propose it? > Again, from > Waldemar's original reply, but with your proposed {{}} interpolated > and the elided code amended to say what the consequence is: > > // outer scope > function c() ...; > > // inner scope > {{ >if (foo) { > const c = 37; >} >... c in your proposal must be hoisted to the {{, >so it can't be function c -- yet it can't be >initialized to 37 if foo is "falsy" ... > }} Yes, c exists in the inner scope {{ }}. It exists there from before you enter the scope and throughout. It shadows the outer c() throughout. If foo is false, the constant c is never initialized. > You could reply that const is new (sort of -- two browsers already > implement it one way, another treats it as var) and therefore should > always scope to { or {{, whichever is closer. But the point stands if > you replace const with function or var and ho
Re: function hoisting like var
On Jul 26, 2008, at 2:06 PM, Ingvar von Schoultz wrote: > How sad! It seemed such a simple and intuitive notation! Opinions vary, but all the ones I heard at the Ecma TC39 meeting found it neither simple nor intuitive, and some abhorred it on aesthetic grounds to boot. > I think all of these would be unambiguous: > > {. code .} > > {: code :} > > {| code |} > > {[ code ]} > > [[ code ]] > > [ code ] These are either syntax errors without opt-in versioning, or (the last three) do create incompatible ambiguity (consider array initialisers). What's more, as Waldemar pointed out many threads (and too many words) ago, they create capture problems. Please work through the last mail I sent before replying; if some vocabulary or infelicitous word choice is causing any confusion, feel free to mail me privately and ask pointed questions. Thanks, /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
On Jul 26, 2008, at 2:07 PM, Ingvar von Schoultz wrote: > You can't get away from supporting this: > > { > function a(){} > var b = a; > } > > ES4 is planning to support function declarations locally > bound in blocks, so the above is valid ES4 code. > > What you see above is function b() hoisting like var. > > (I said b, not a.) What you said does not make sense. It's true that var b is hoisted to the top of the program or function body. But it is not initialized until control flows through the assignment b = a that is part of the var declaration. So there is no capture problem. > There is no far-too-complicated split-scope complexity. There > is no capturing of variables that haven't been declared yet. > It's simple, intuitive, well-defined and well-behaved. Thanks, I agree. But it is not what you proposed. Again, from Waldemar's original reply, but with your proposed {{}} interpolated and the elided code amended to say what the consequence is: // outer scope function c() ...; // inner scope {{ if (foo) { const c = 37; } ... c in your proposal must be hoisted to the {{, so it can't be function c -- yet it can't be initialized to 37 if foo is "falsy" ... }} You could reply that const is new (sort of -- two browsers already implement it one way, another treats it as var) and therefore should always scope to { or {{, whichever is closer. But the point stands if you replace const with function or var and hoist to the {{. Repeating the next counter-example, with {{}} changes again, to track your proposal since the original exchange with Waldemar: // outer scope function c() ...; // inner scope {{ function f() { return c; } a = f(); if (foo) { const c = 37; } b = f(); ... just what do a and b hold here? Was f's captured variable rebound by the if statement? ... }} And so on. > The above is the /exact/ functionality of function hoisting > like var, apart from using two names. You can refuse the > clearer syntax, but you can't refuse the above code and > functionality. I think I see the confusion now. Do you believe that in the var b = a; code you wrote, both the binding of the var named b *and* its initialization with the value of the function object denoted a are hoisted? Hoisted up to what point? Waldemar wrote a while back: "Keep in mind that function assignments hoist to the beginning of the scope in which the function is defined, so your proposal won't work." The word "assignment" where "definition" was perhaps more precise (function definitions replace extant properties of the same name in the variable object, they are not equivalent to assignment expressions) may have misled you. From the context and the long- standing spec and implementation behavior with functions not in blocks or any other sub-statement position, it was clear (I think) what was meant, but I can see how this could be confusing. Assignment expressions and initializers in var statements do not hoist or otherwise move in the flow of control. /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
2008/7/26 Ingvar von Schoultz <[EMAIL PROTECTED]>: > I think all of these would be unambiguous: > >{. code .} {. not work since {.0; } is a valid ES3 > >{: code :} > >{| code |} These 2 cases are indeed invalid ES3. > >{[ code ]} > >[[ code ]] > >[ code ] Any of this can be a valid ES3 code as [] always means an array literal. Regards, Igor ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Brendan Eich wrote: > Waldemar meant precisely what he wrote: ES3 and draft ES3.1 -- the > specifications, not random JS implementations. Oops, I got lost in details and strayed far away from the point that I wanted to make. In fact I should have said this from the beginning: You can't get away from supporting this: { function a(){} var b = a; } ES4 is planning to support function declarations locally bound in blocks, so the above is valid ES4 code. What you see above is function b() hoisting like var. (I said b, not a.) There is no far-too-complicated split-scope complexity. There is no capturing of variables that haven't been declared yet. It's simple, intuitive, well-defined and well-behaved. The above is the /exact/ functionality of function hoisting like var, apart from using two names. You can refuse the clearer syntax, but you can't refuse the above code and functionality. In other words, complexity is not a problem. ES4 can easily choose whatever semantics people prefer. -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Igor Bukanov wrote: > 2008/7/26 Ingvar von Schoultz <[EMAIL PROTECTED]>: >> Do you really think {{ }} appears in existing code, correctly >> enclosing statement blocks, with the {{ and the }} placed tightly >> together both at the beginning and at the end? > > Yes: I have seen the code like > > if (x) { >{ > code >} > } > > Now pass through a JS compressor that removes redundant whitespace and > you get precizelly {{ }}. > > In addition, those {{ can happen in a code generator. > > Regards, Igor > ___ > Es4-discuss mailing list > Es4-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es4-discuss > How sad! It seemed such a simple and intuitive notation! I think all of these would be unambiguous: {. code .} {: code :} {| code |} {[ code ]} [[ code ]] [ code ] -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
2008/7/26 Ingvar von Schoultz <[EMAIL PROTECTED]>: > Do you really think {{ }} appears in existing code, correctly > enclosing statement blocks, with the {{ and the }} placed tightly > together both at the beginning and at the end? Yes: I have seen the code like if (x) { { code } } Now pass through a JS compressor that removes redundant whitespace and you get precizelly {{ }}. In addition, those {{ can happen in a code generator. Regards, Igor ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
On Jul 26, 2008, at 4:03 AM, Ingvar von Schoultz wrote: [EMAIL PROTECTED] wrote: Ingvar von Schoultz wrote: [EMAIL PROTECTED] wrote: I'm trying to keep the language relatively simple. You can't get away from supporting this: { function a(){} var b = a; } What do you mean? This is a syntax error in both ES3 and ES3.1. It works fine in Firefox 2, Konqueror 3, Opera 9, Internet Explorer 6, and server-side Rhino with JavaScript 1.6. Waldemar meant precisely what he wrote: ES3 and draft ES3.1 -- the specifications, not random JS implementations. Five platforms out of five. Can you throw a syntax error here and claim to be compatible? The implementations are not compatible. Please see the earlier es4- discuss thread with subject "Function declarations in statements" at: https://mail.mozilla.org/pipermail/es4-discuss/2007-March/ thread.html#527 It does not already exist in ES3 or ES3.1. It exists on platforms as described above. I assumed that ES4 would be compatible. No, because it is impossible to be compatible with conflicting extensions to ES3 that browsers have implemented. The conflicts and undesirable intersection semantics are why ES4 proposes, and ES3.1 considered but deferred, block-scoped functions that must be direct children of braced blocks. This requires opt-in versioning, which is why ES3.1 deferred it. /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
[EMAIL PROTECTED] wrote: > Ingvar von Schoultz wrote: >> [EMAIL PROTECTED] wrote: >>> I'm trying to keep the language relatively simple. >> You can't get away from supporting this: >> >> { >> function a(){} >> var b = a; >> } > > What do you mean? This is a syntax error in both ES3 and ES3.1. It works fine in Firefox 2, Konqueror 3, Opera 9, Internet Explorer 6, and server-side Rhino with JavaScript 1.6. Five platforms out of five. Can you throw a syntax error here and claim to be compatible? You can test it in browsers at http://test-a-1.appjet.net/ Below is a more detailed example that also includes let. It uses JavaScript 1.7 and works in Firefox 2. You can test it at http://test-a-2.appjet.net/ alert (b); { function a(){} var b = a; let c = 3; alert (c); } alert (b); alert (typeof c); >> On the contrary, the functionality already exists, as shown >> above. > > It does not already exist in ES3 or ES3.1. It exists on platforms as described above. I assumed that ES4 would be compatible. >>> Keep in mind that function assignments hoist to the beginning of the >>> scope >>> in which the function is defined, so your proposal won't work. >> When the programmer explicitly says that the assignment depends >> on sequential code, then do what the programmer says. Anything >> else is an error. Do it by assigning |undefined| before scope >> entry. This is the only correct thing to do. > > I don't understand. In all normal cases the function is assigned at the beginning of the scope. However, there are some special cases where this would be an incorrect interpretation of the source code. If the programmer clearly says that the assignment is /unknown/ at the beginning of the scope, then assigning prematurely would be wrong. For example, the programmer might say: if (Math.random() < 0.5) function f() {return 1} else function f() {return 2} Implementations vary here, but let's assume that it is defined to mean what it says. Then f will be assigned either the first or the second body, depending on the random number. This decision comes /after/ you enter the scope. The assignment depends on something that happens /inside/ the scope. Therefore, here the programmer is saying quite clearly that the assignment is /unknown/ at the beginning of the scope. It would be wrong for the compiler to guess. The solution is to assign |undefined| at the beginning of the scope. This situation is unusual. It happens only when the programmer says that the assignment is unknown at the beginning of the scope, as above. >> The function /body/ stays where it is. The hoisting doesn't >> affect it in any way. Moving the body would change its context >> and meaning catastrophically. Don't touch it. > > That doesn't answer the question. The problem is that the body can > capture variables that haven't been declared yet. With suitable arrangements this becomes impossible. Of course if you /insist/ on setting everything up and assigning to the function name before the body's context exists, then you can't expect it to work. Then you get an incorrect program that will act as you say. That's to be expected if you allow calling a function whose context doesn't exist. But if you accept that when the context doesn't exist you should assign |undefined| at the beginning of the scope, and only assign the body later, when its context does exist, then you get a well- defined and well-behaved program. Then any premature call to the function will throw an error as a call to undefined(). This will work in ways that the programmer can understand well. As far as I can tell, this is correct by definition. Can you find an example where it breaks? >> The /name/ becomes a var. Treat it like any other var. Hoist >> it and assign |undefined|, exactly like you do with other vars. > > That's incompatible with how functions are defined in ES3. Incompatible? Your comment on my tiny two-line program says that you want to throw a syntax error in these cases. Breaking five platforms out of five is less compatible than what I describe. It certainly doesn't break JavaScript 1.7 in Firefox. It's almost exactly what Firefox does in this special situation. According to at least one discussion in the ES3.1 archives, ES3 does not specify how you should treat a function in this special situation. Here's one of these comments: https://mail.mozilla.org/pipermail/es4-discuss/2008-July/003142.html >> Are you saying that because this var is related to a function >> it can't be treated like other vars? Is this var fundamentally >> different from other vars? At least above it isn't. > > Huh? Do you understand how ES3 works? Yes, I know it quite well. I've been using JavaScript near full-time on the client since Netscape 3, and on both server and client since Microsoft ASP with JScript first appeared. But why do you refer to ES3? ES3 doesn't ha
Re: function hoisting like var
Igor Bukanov wrote: > Of cause, if desired, such shortcut should be > pure syntax extension over ES3, not {{ }} as that silently changes the > meaning of the existing code. Do you really think {{ }} appears in existing code, correctly enclosing statement blocks, with the {{ and the }} placed tightly together both at the beginning and at the end? I find this somewhat unlikely, since it's a redundant repetition that means exactly the same as { }. Ingvar Igor Bukanov wrote: > 2008/7/25 Lars Hansen <[EMAIL PROTECTED]>: >> Is >> >> {{ return }} >> >> syntactic sugar for >> >> (function() {{ return }})() >> >> too? > > I have forgot about the return or break/continue. But this is not a > point since a syntax sugar for (function() { code })() can require > that code must not contain return or break/continue outside the code > effectively making it a let expression on steroids. The point is that > is it worth to provide a shortcut for (function() { code })() since > that is used on web. Of cause, if desired, such shortcut should be > pure syntax extension over ES3, not {{ }} as that silently changes the > meaning of the existing code. > > One way to get that extension comes from an observation that ES4 > allows to drop the braces around function body and the return keyword > if the body is the single return exp. If ES3.1 would support it, then > to simulate an effect of let expression like > > let (a = arg1, b = arg2) expression > > one could write > > (function(a, b) expression)(arg1, arg2) > > or > > (function(a, b) a = arg1, b = arg2, expression)() > > If, in addition to this shortcut, ES4 would allow to drop an empty > argument list from a function with a requirement that function { } > always means an expression and ES3.1 would also support that, then in > place of a block with let variables one can write: > > function { > > }(); > > Regards, Igor > ___ > Es4-discuss mailing list > Es4-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es4-discuss > -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Igor Bukanov wrote: > I guess that proposal can be summarized in a very short form: > > make > > {{ code }} > > a syntax sugar for > > (function() { code })() Indeed you're right. When I proposed {{ }} my intent was simplicity, but I didn't realize that implementing it could be made that simple, the change that small. By the way, your translation (function() { code })() can also be expressed as new function() { code } Less parentheses! (But I haven't explored possible drawbacks.) -- Ingvar von Schoultz --- (My quirky use of capitals in code comes from my opinion that reserved and predefined words should all start with lowercase, and user-defined should all start with uppercase, because this will easily and elegantly prevent a host of name-collision problems when things like programming languages are upgraded with new labels.) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
On 2008-07-25, at 10:17EDT, Lars Hansen wrote: > Even neater, using default argument values the syntax is actually > > (function (a=arg1, b=arg2) expression)() > > at which point 'let' is a trivial transformation. For some reason, the words 'lambda' and 'ultimate' spring to mind... :P ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: function hoisting like var
> -Original Message- > From: Igor Bukanov [mailto:[EMAIL PROTECTED] > Sent: 25. juli 2008 14:36 > To: Lars Hansen > Cc: [EMAIL PROTECTED]; [EMAIL PROTECTED]; es4- > [EMAIL PROTECTED]; Ingvar von Schoultz > Subject: Re: function hoisting like var > > One way to get that extension comes from an observation that ES4 > allows to drop the braces around function body and the return keyword > if the body is the single return exp. If ES3.1 would support it, then > to simulate an effect of let expression like > > let (a = arg1, b = arg2) expression > > one could write > > (function(a, b) expression)(arg1, arg2) > > or > > (function(a, b) a = arg1, b = arg2, expression)() > > If, in addition to this shortcut, ES4 would allow to drop an empty > argument list from a function with a requirement that function { } > always means an expression and ES3.1 would also support that, then in > place of a block with let variables one can write: > > function { > > }(); Even neater, using default argument values the syntax is actually (function (a=arg1, b=arg2) expression)() at which point 'let' is a trivial transformation. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
2008/7/25 Lars Hansen <[EMAIL PROTECTED]>: > Is > > {{ return }} > > syntactic sugar for > > (function() {{ return }})() > > too? I have forgot about the return or break/continue. But this is not a point since a syntax sugar for (function() { code })() can require that code must not contain return or break/continue outside the code effectively making it a let expression on steroids. The point is that is it worth to provide a shortcut for (function() { code })() since that is used on web. Of cause, if desired, such shortcut should be pure syntax extension over ES3, not {{ }} as that silently changes the meaning of the existing code. One way to get that extension comes from an observation that ES4 allows to drop the braces around function body and the return keyword if the body is the single return exp. If ES3.1 would support it, then to simulate an effect of let expression like let (a = arg1, b = arg2) expression one could write (function(a, b) expression)(arg1, arg2) or (function(a, b) a = arg1, b = arg2, expression)() If, in addition to this shortcut, ES4 would allow to drop an empty argument list from a function with a requirement that function { } always means an expression and ES3.1 would also support that, then in place of a block with let variables one can write: function { }(); Regards, Igor ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: function hoisting like var
Is {{ return }} syntactic sugar for (function() {{ return }})() too? --lars > -Original Message- > From: [EMAIL PROTECTED] [mailto:es4-discuss- > [EMAIL PROTECTED] On Behalf Of Igor Bukanov > Sent: 25. juli 2008 13:34 > To: [EMAIL PROTECTED] > Cc: [EMAIL PROTECTED]; es4-discuss@mozilla.org; Ingvar von > Schoultz > Subject: Re: function hoisting like var > > I guess that proposal can be summarized in a very short form: > > make > > {{ code }} > > a syntax sugar for > > (function() { code })() > > On a few occasions I have used the latter form in ES3 programs to get > the benefits of the let locals without using the let keyword. > > Regards, Igor > ___ > Es4-discuss mailing list > Es4-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
I guess that proposal can be summarized in a very short form: make {{ code }} a syntax sugar for (function() { code })() On a few occasions I have used the latter form in ES3 programs to get the benefits of the let locals without using the let keyword. Regards, Igor ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: function hoisting like var
Ingvar von Schoultz wrote: > [EMAIL PROTECTED] wrote: >> I'm trying to keep the language relatively simple. > > You can't get away from supporting this: > > { > function a(){} > var b = a; > } What do you mean? This is a syntax error in both ES3 and ES3.1. > On the contrary, the functionality already exists, as shown > above. It does not already exist in ES3 or ES3.1. >> Keep in mind that function assignments hoist to the beginning of the >> scope >> in which the function is defined, so your proposal won't work. > > When the programmer explicitly says that the assignment depends > on sequential code, then do what the programmer says. Anything > else is an error. Do it by assigning |undefined| before scope > entry. This is the only correct thing to do. I don't understand. >> You're >> trying to do a complex split-scope approach where each function >> definition >> has *two* scopes, one in which it is declared and one in which it is >> defined, but even that won't work with const, typed functions and >> variables, etc. > > Are you saying that the function /body/ gets into trouble, > or the function /name/? Both. > The function /body/ stays where it is. The hoisting doesn't > affect it in any way. Moving the body would change its context > and meaning catastrophically. Don't touch it. That doesn't answer the question. The problem is that the body can capture variables that haven't been declared yet. > The /name/ becomes a var. Treat it like any other var. Hoist > it and assign |undefined|, exactly like you do with other vars. That's incompatible with how functions are defined in ES3. > Are you saying that because this var is related to a function > it can't be treated like other vars? Is this var fundamentally > different from other vars? At least above it isn't. Huh? Do you understand how ES3 works? > That email is about some wildly unworkable dynamic scoping. > It has nothing to do with anything I ever said. You jumped > to that conclusion. > > Please stop insisting that I'm proposing that nonsense. I'm > not. I never did. I haven't seen a sensible and compatible proposal yet. >> You'd then have to >> introduce extra rules about some definitions only being possible within >> {{}} blocks, which would then affect the behavior of existing definitions >> like var if one of the other definitions within the same block was a >> const >> or function, which would snowball into a complex mess. > > Unrelated, I believe. So you're saying that your {{}} proposal has nothing to do with this? Waldemar ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss