(Almost) everything is expression

Dmitry Soshnikov dmitry.soshnikov at gmail.com
Fri Nov 11 04:14:39 PST 2011


On 11.11.2011 15:48, François REMY wrote:
> I think you strongly underestimate the "distinction" problem. It's 
> *not* possible to make any difference between the "foo" statement and 
> the "print" statement of your sample, from the compiler point of view. 
> Why would the "foo" statement be the one chosen as a return value for 
> the "if" block? It's completelty unclear to me. If there's no way to 
> tell what the "return statement" of the block is, there's no way to 
> implement your proposal.

Currently the last evaluated statement of a block is the result of the 
block (see 12.1). That's said, manual `return` contradicts TCP, so I 
noted it only as additional topic to consider. The main feature -- just 
the last evaluated statement is the result of the block -- as it's not 
at implementation level.

> It's not because the goal of the code seems clear to an human it will 
> be equally clear to a compiler, because it's a completely different 
> story there.
>
> Let me introduce a sample :
>
>    let x = if(test) {
>        translate("test was true");
>    } else {
>        translate("test was false");
>    }
>
> vs
>
>    let x = if(test) {
>        print("test was true");
>        a+b;
>    } else {
>        print("test was false");
>        a-b;
>    }
>
> The "print" and the "translate" statement are identical, but they 
> don't have the same "translation" since only one becomes an 
> assignation. The "do" syntax solves this problem with a "return" 
> statement, but you can't imagine that for each statement, like a "if", 
> right?
>

I don't see the problem here. In first example the result of the if is 
the result of translate("test was true");  in case if `test` is 
evaluated to `true` (with any acceptable boolean coercions), or it's the 
result of evaluating of translate("test was false"); in other case.

> My guess is that the value of a statement (in your proposed syntax) 
> could be the return value of the latest statement evaluated in the 
> block. The problem is that it may be unknown at compilation time... or 
> isn't it?
>

How the compilation time is related here? Once again, we need only the 
ability to assign results of statement evaluations (thus, automatically 
turning them into expressions). Since statements at implementation level 
return values, the only change is to fix assignment -- to allow those 
statement on the RHS.

Dmitry.

>
>
> -----Message d'origine----- From: Dmitry Soshnikov
> Sent: Friday, November 11, 2011 12:21 PM
> To: François REMY
> Cc: David Herman ; es-discuss Steen
> Subject: Re: (Almost) everything is expression
>
> On 11.11.2011 14:44, François REMY wrote:
>> I didn't read your first mail, I've to acknowledge. That doesn't 
>> change the fact the sample was reinventing the wheel.
>>
>
> I still don't see how your this sentence helps taking into account that
> I myself noted this case, sorry.
>
>> BTW,your samples all suffer from a big ambuiguity that I think is 
>> unresolvable.
>>
>>    let a = if (foo) {
>>       print('a is foo');
>>       foo;
>>    } else {
>>       // do some longer stuff
>>    };
>>
>> How do you know "foo" is an expression that should be assigned to "a" 
>> and that "print('a...')" is not?
>>
>
> Please concentrate on the main problem. Don't consider now some small
> non-essential issues of examples. In this proposal and the exact example
> it doesn't matter what is `foo` and to what it can be assigned.
>
>> In ECMAScript, each statement returns a value.
>
> At implementation level. And it's good. It means the implementation will
> not require much modifications, since e.g. Block statement (12.1, ES5.1)
> returns as a result the value of last evaluated statement. So the thing
> is just allow this result to be assigned to the LHS. In other words, the
> ability to make the block and other statements as RHS, e.g. to make them
> expressions.
>
>> There's no way to find out if the statement is a "normal" statement 
>> or a "value" statement. To my understanding, there's no.
>>
>>    let a = try {
>>        if(test()) {
>>            translate("test was true")
>>        } else {
>>            translate("test was false")
>>        }
>>    } catch(ex) {
>>        translate("test has raised an exception")
>>    }
>>
>
> Yes, this is completely OK. No worries for implementation. The only
> thing is to allow this `try` be RHS of the assignment. Now it's a syntax
> error.
>
>> Secondly, is it worth modifying the UA's compilers and JS syntax? 
>> What's what you gain, in terms of readability, in terms of facility, 
>> ... ?
>>
>
> I think it worth. Again, after Erlang I felt inconvenient that I have to
> (1) declare a var above and (2) provide assigned to the var in two
> (e.g.) if branches. I want to write only one assignment and to tell that
> the result of the assignment is the result of evaluating this complex
> expression. It's more convenient than to look inside long block body and
> to understand whether it assigns to outer var or not.
>
>>
>>
>> PS: I don't know what is the "do" syntax you reference but I guess it 
>> solves the ambiguity problem by creating a kind of "block lambda". 
>> Value statements can be recognized by a "return" statement inside the 
>> block.
>>
>>    let a = do {
>>        if(test()) {
>>            return translate("...");
>>        } else {
>>            return translate("...");
>>        }
>>    }
>>
>> In such case "do { ... }" is just a sugar for (function() { ...})(). 
>> It could be used to make more beautiful the "module" pattern used in 
>> many codes now.
>>
>>
>
> Yep. Though, we have already such a sugar for immediately applied lambda
> -- it's a let-statement:
>
> let (a = 10, b = 20) {
>   // do stuff
> }
>
> in many implementations are just a sugar of
>
> (function (a, b) {
>   // do stuff
> })(10, 20);
>
> Dmitry.
>
>>
>>
>> -----Message d'origine----- From: Dmitry Soshnikov
>> Sent: Friday, November 11, 2011 10:42 AM
>> To: François REMY
>> Cc: David Herman ; es-discuss Steen
>> Subject: Re: (Almost) everything is expression
>>
>> On 11.11.2011 13:26, François REMY wrote:
>>> <aside note>
>>>
>>>    let x = q ? 10 : 20;
>>>
>>>    Why we're reinventing the wheel here is up to me.
>>>
>>> </aside>
>>>
>>
>> I noted it in the initial letter. Yes, we have the sugar for this
>> particular case for years (the ternary operator). But also with this I
>> mention that it doesn't allow _conveniently_ handle complex bodies of
>> consequent and alternative nodes of an if-expression. Please re-read my
>> initial letter.
>>
>> Once again, the idea is to have _in addition_ for all the statement
>> parts the same expression parts (not only for if-statement, so sorry, I
>> don't buy your "reinventing the wheel").
>>
>> And since this is exactly the _addition_, but _not the replacement_,
>> it's still possible to use statement forms (w/o explicit semicolon). But
>> if you need an expression form, use it. The same as with FD and FE.
>>
>> Dmitry.
>>
>>> -----Message d'origine----- From: Dmitry Soshnikov
>>> Sent: Friday, November 11, 2011 8:54 AM
>>> To: David Herman
>>> Cc: es-discuss Steen
>>> Subject: Re: (Almost) everything is expression
>>>
>>> On 11.11.2011 11:43, David Herman wrote:
>>>>> Brendan and Dave mention explicit semicolon. Yes, it's seems so by 
>>>>> the grammar (though, have to check more precisely), but it can be 
>>>>> acceptable price.
>>>> It's a serious price, though. Today if I write:
>>>>
>>>>      if (q) { ... }
>>>>      else { ... }
>>>>      (f())
>>>>
>>>> then ASI kicks in after the else body. If we make if-statements 
>>>> into expressions, then either the above becomes a single 
>>>> expression, which is a serious and subtle backwards-incompatible 
>>>> change, or we define lookahead restrictions on ExpressionStatement, 
>>>> and introduce a refactoring hazard:
>>>>
>>>>      x = if (q) { ... }
>>>>          else { ... }
>>>>      (f())                 // oops, this is now a parameter list on 
>>>> the RHS of the assignment!
>>>>
>>>> I'm not positive, but that seems like a serious issue to me.
>>>
>>> Yes, all this relatively true, but personally I don't see the big 
>>> issue.
>>> In practice we already have such a case e.g. for FD (function
>>> declaration) vs. FE (function expression).
>>>
>>> The former doesn't require semicolon, the later does. Though, in the
>>> later case (FE), today most of programmers put explicit semicolon to
>>> avoid problems with scripts minimizing. From this viewpoint it's not a
>>> big price, since even now the programmers are already used to such 
>>> cases.
>>>
>>> Regarding old code it's also not the issue since there is no such old
>>> code, it's a syntax error. And even if a user will refactor code (to
>>> make it look shorter and elegantly), she should be aware about this 
>>> case
>>> (again -- just like with FD and FE -- users are aware about it):
>>>
>>> Was:
>>>
>>> var x;
>>>
>>> if (q) {
>>>   x = 10;
>>> } else {
>>>   x = 20;
>>> }
>>>
>>> Becomes:
>>>
>>> let x = if (q) {
>>>   10;
>>> } else {
>>>   20;
>>> };
>>>
>>>>> Nope, have to think more on this...
>>>> You might want to take a look at this:
>>>>
>>>>
>>>> http://wiki.ecmascript.org/doku.php?id=strawman:block_vs_object_literal 
>>>>
>>>>
>>>
>>> Yep, I've seen it before briefly; will check it more precisely later,
>>> thanks.
>>>
>>> Dmitry.
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>
>



More information about the es-discuss mailing list