Re: How to escape implicit 'with (this)' of a method body

2008-07-29 Thread P T Withington
On 2008-07-29, at 01:19EDT, Brendan Eich wrote:

 On Jul 28, 2008, at 10:05 PM, Jon Zeppieri wrote:

 The original code used without (this), not with, which I took to  
 mean avoid instance properties shadowing globals.

Indeed.  Perhaps I was being too clever in my pseudo-code.

 If you read the original as with, then there is no such problem.  
 But if you construct a problematic case using 'with' and dynamic  
 properties, then I concede that 'global' could be shadowed. This is  
 a reason to avoid 'with'. In the ES4 proposals last sent out, you  
 could always use __ES4__::global if you really wanted to avoid  
 conflicts -- unless someone perversely added '__ES4__' as a dynamic  
 instance property.

 There's no solution to this problem other than reserving at least  
 one name, and we can't do that compatibly. We could reserve __ES4__  
 in version-selected ES4 mode, but that seems unnecessary.

I guess this is considered a small penalty to pay in exchange for  
adding the magical instance scope to methods (which O-O programmers  
seem to expect these days).  Something we'd regret more if we had  
multi-methods, perhaps...
___
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.)