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
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: 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
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
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 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.)