Re: A simple translation of the scoping-block syntax sugar -- Was: Re: function hoisting like var

2008-07-30 Thread Ingvar von Schoultz
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

2008-07-29 Thread Ingvar von Schoultz
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

2008-07-29 Thread Ingvar von Schoultz
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

2008-07-29 Thread Ingvar von Schoultz
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

2008-07-29 Thread Ingvar von Schoultz
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.)