Expression closures - use-cases for shortcut lambda syntax (blocks)

Dave Herman dherman at ccs.neu.edu
Sat Mar 17 04:55:38 PDT 2007


Let me see if I understand your proposal. I will try to make it concrete 
and semi-precise, but correct my misunderstandings:

   1) add a production to the grammar allowing block statements to be 
used as expressions, roughly Expression ::= ... | Block

   2) treat such a block <b> as syntactic sugar for function()<b>

If a block statement can be used as an expression, how do we 
disambiguate from object literals?

     // empty object or empty block?
     foo(1, 2, {}, 3, 4)

     // block with stmt labelled "lab"? object with property named "lab"?
     foo(1, 2, {lab: bar()}, 3, 4)

I'm sort of sympathetic to your idea as analogous to Smalltalk and Ruby 
blocks. But I'm not sure it's even workable syntactically. Also, the 
curly brace is very overloaded in this language, so there's a serious 
cost involved in overloading it yet again.

If, OTOH, you're only proposing such expressions be legal in more 
restricted syntactic contexts (you said something like "following a 
function call expression") then I think your case is even weaker. It 
doesn't make sense to have a syntactic sugar for function expressions 
that can only be used in a fraction of the contexts where the real 
syntax can be used. I suspect it'll just confuse matters and people will 
adopt a "don't use block expressions 'cause they don't always work and 
function expressions always do" policy.

I also don't like the asymmetry with lack of named arguments. This will 
prevent people from ever putting type annotations on these expressions.

Dave

Neil Mix wrote:
> On Mar 17, 2007, at 12:44 AM, Brendan Eich wrote:
> 
>> Test that claim: show those Mochikit examples rewritten to use
>> expression closures as proposed for ES4.
> 
> Yes, of course.  Here are Robert's examples using the \( syntax:
> 
> addLoadEvent(\() {
>      var elems = getElementsByTagAndClassName("A", "view-source");
>      var page = "rounded_corners/";
>      for (var i = 0; i < elems.length; i++) {
>          var elem = elems[i];
>          var href = elem.href.split(/\//).pop();
>          elem.target = "_blank";
>          elem.href = "../view-source/view-source.html#" + page + href;
>      }
> });
> 
> addLoadEvent(\() {
>          $("debug").innerHTML = repr(getElementPosition($("street")));
>          $("debug").innerHTML += "<br>";
>          $("debug").innerHTML += repr(quirksmode.findPos($("street")));
> });
> 
> addLoadEvent(\(){
>    for(var _70 in DomDeco.registry){
>      for(var i=0;i<DomDeco.registry[_70].length;i++){
>        DomDeco.apply(_70,DomDeco.registry[_70][i]);
>     }
>    }
> });
> 
> addLoadEvent(\() {
>       var d = wait(0.5, {data: [["getUsers", "getUsers"], ["foo",   
> "bar"]]});
>       d.addCallback(showSelectData);
>       d.addErrback(showError);
> });
> 
> 
> Nested anonymous functions:
> ------------------------------------------
> addLoadEvent(\(){
>      connect('pagelist','onclick', \(e) {
>      e.preventDefault();
>      var d = loadJSONDoc("${std.url('/pagelist', tg_format='json')}");
>      d.addCallback(showPageList);
>      });
> });
> 
> addLoadEvent(\(){
>      connect('bad_example','onclick',
>          \(e){signal('bad_example','showvalue',"explicit_value")});
>      connect('bad_example','showvalue',window,'alert');
> 
>      connect('good_example','onclick',
>          \(e){signal(randomObj,'showvalue',"explicit_value")});
>      connect(randomObj,'showvalue',window,'alert');
> });
> 
> 
> 
> Now, to back up my assertion that the curlies and parens are  
> cluttering things up (and NOT to re-open my earlier proposal because  
> that door has already been shut, right?) here's the same code using  
> the block-following-call-becomes-lambda-arg syntax:
> 
> addLoadEvent() {
>      var elems = getElementsByTagAndClassName("A", "view-source");
>      var page = "rounded_corners/";
>      for (var i = 0; i < elems.length; i++) {
>          var elem = elems[i];
>          var href = elem.href.split(/\//).pop();
>          elem.target = "_blank";
>          elem.href = "../view-source/view-source.html#" + page + href;
>      }
> }
> 
> addLoadEvent() {
>          $("debug").innerHTML = repr(getElementPosition($("street")));
>          $("debug").innerHTML += "<br>";
>          $("debug").innerHTML += repr(quirksmode.findPos($("street")));
> }
> 
> addLoadEvent() {
>    for(var _70 in DomDeco.registry){
>      for(var i=0;i<DomDeco.registry[_70].length;i++){
>        DomDeco.apply(_70,DomDeco.registry[_70][i]);
>     }
>    }
> }
> 
> addLoadEvent() {
>       var d = wait(0.5, {data: [["getUsers", "getUsers"], ["foo",   
> "bar"]]});
>       d.addCallback(showSelectData);
>       d.addErrback(showError);
> }
> 
> 
> Nested anonymous functions:
> ------------------------------------------
> addLoadEvent() {
>      connect('pagelist','onclick') {
>      e.preventDefault();
>      var d = loadJSONDoc("${std.url('/pagelist', tg_format='json')}");
>      d.addCallback(showPageList);
>      }
> }
> 
> addLoadEvent() {
>      connect('bad_example','onclick') {
>          var [e] = arguments;
>          signal('bad_example','showvalue',"explicit_value")
>      }
>      connect('bad_example','showvalue',window,'alert');
> 
>      connect('good_example','onclick') {
>          var [e] = arguments;
>          signal(randomObj,'showvalue',"explicit_value")
>      }
>      connect(randomObj,'showvalue',window,'alert');
> }
> 
> 
> I argue that both are confusing at first glance, but the latter is  
> more legible.  (Again, not as a suggestion that it be adopted, but as  
> proof of my assertion that many dense curlies/parens are the  
> legibility problem rather than the function keyword.)
> 
> _______________________________________________
> Es4-discuss mailing list
> Es4-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es4-discuss




More information about the Es4-discuss mailing list