A simple translation of the scoping-block syntax sugar -- Was: Re: function hoisting like var
Ingvar von Schoultz
ingvar-v-s at comhem.se
Tue Jul 29 17:17:12 PDT 2008
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.)
More information about the Es4-discuss
mailing list