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