Proposal: expression mode (=)

# Yongxu Ren (8 years ago)

This proposal makes it easier to write functional code, you can convert statements block into expressions producing a useful result and plugging that back into an expression context.

This proposal is an alternative to the 'do expressions'.

Prepending = will automatically convert if...else, switch..., block into statement that returns last inner statements value by default.

examples:


// the following 3 lines are equivalent

console.log(=if (expr) {a} else {b})

console.log(=if (expr) a else b)

console.log(expr ? a : b)

// print the value of statement3

console.log(={

  statement1

  statement2

  statement3

})

If the left hand side is an expression or operator, '=' can be omitted


LeftHandSideExpression = if (condition)

   statement1

[else

   statement2]

let someVal = LeftHandSideExpression * if (condition)

   statement1

[else

   statement2]

examples:


// the following 3 examples are equivalent

let x = if (expr) {a} else {b}

let x = if (expr) a else b

let x = expr ? a : b


let x = {

// statements here

console.log('print unicorn')

y // will assign y to x

}

# Yongxu Ren (8 years ago)

potentially, this syntax can be extended to functions

function f() ={stat}
// is equivalent to
function f() {return stat}


let f = () => ={stat}
// are equivalent to
let f = () => stat

it can also be applied to try...catch.... and more, such as

// pattern matching
match(expr) {
  pattern1:={
    //block
  }
  pattern2:={
    //block
  }
  pattern3:={
    //block
  }
}
# Olivier Lalonde (8 years ago)

Sounds like the "do expressions" proposal. strawman:do_expressions

# Yongxu Ren (8 years ago)

Yes, it does the exact same thing. I think using = and operators is a bit cleaner than 'do'. However, The biggest advantage for this feature is you can write functional code without extra syntax. Allowing block to return value will allow you to write concise code like in ocaml Haskell or scala.

# JongChan Choi (8 years ago)

OMG sweet! I love it. then how it’ll be formed when mixed with labeled statement?

# JongChan Choi (8 years ago)

ambiguous case

let x = {
    // statements here?
    label: ’value'
};
# Yad Smood (8 years ago)

I think label: ’value' is not a legal statement I think, so you actually can distinguish them.

# Caitlin Potter (8 years ago)

On Oct 30, 2016, at 10:45 AM, Yad Smood <y.s.inside at gmail.com> wrote:

I think label: ’value' is not a legal statement I think, so you actually can distinguish them.

"use strict"; is a valid Statement, so why not?

My read of this was that it uses := instead of = to work around this ambiguity.

I think the do-expressions idea is more powerful, though, since it's a valid RHS operand to any binary op, whereas this looks limited to assignment.

# Caitlin Potter (8 years ago)

Ah, nevermind, I guess := was just used in the pattern matching example. So, there is a grammar ambiguity here.

# Yongxu Ren (8 years ago)

For supporting label, yes that is kinda a problem. However, IMO jumping around labels is an anti-pattern in functional programming, I don't think it needs to be supported. Syntax error might be the most reasonable way in this case.

for 'match', while it is just some thought. I wasn't intended to proposal it but just showing potential of extending = expression.

Personally I do not think label would be a problem for implementing this pattern.

here are two possible solutions I can think of:

  1. If [name]: exist inside the block, just parse it as object and throw error if the structure doesn't match.

  2. If [label]: does exist inside the block, only allow in scope jump. (label not accessible outside the scope)

# Isiah Meadows (8 years ago)

For what it's worth, if the = requires a space before it (I disagree that the semantic ambiguity must exist at assignment - it could simply require whitespace), that alone would create sufficient context to differentiate. Compare these two:

a == {} // loose equals, almost always false
a = = {} // a = undefined

Labels would already be unambiguous, because it can only parse statements.

Here's my concern about ambiguity, though:

var b = 1
var a = b
= { c }

What's a? ASI makes this much less obvious to resolve, and resolving this by changing assignment to require no line terminator before the = is technically a breaking change. (Oh, and the Closure Compiler can and will spit out that.)

# Yongxu Ren (8 years ago)

Isiah, The reason for = instead of the do expression is to write functional code without extra syntax. I do not think there are any indistinguishable or 'very confusing' case, though I am aware the *Object Property Shorthand` that been introduced in ES6 might cause some problems.

Here is what I think that may resolve this problem for your concern,

var b = 1
var a = b
= { c }

the solution is to make Object literals to have higher parsing priority.

if c is a variable, it will be parsed as object literal, otherwise it is considered as scope and been parsed as expression block.

ex. var x = { a } will be parsed as var x = { a: a } var x = { a() } will be parsed as var x = a(), under current specs it would be syntax error.

In this case, this proposal should not cause any confusion IMO.

# Isiah Meadows (8 years ago)

Not quite. I did some later thinking, and hage found probably a simpler solution.

On Mon, Oct 31, 2016, 16:10 Yongxu Ren <renyongxu at gmail.com> wrote:

Isiah, The reason for = instead of the do expression is to write functional code without extra syntax. I do not think there are any indistinguishable or 'very confusing' case, though I am aware the *Object Property Shorthand` that been introduced in ES6 might cause some problems.

Here is what I think that may resolve this problem for your concern,

var b = 1
var a = b
= { c }

the solution is to make Object literals to have higher parsing priority.

Actually, the above example should read as this:

a
= { b }

First, most linters will complain, anyways.

Second, it could be resolved by requiring no line terminator appears between the assignee and = operator. The Closure Compiler is okay with emitting such code normally, but no other minifier does by default. And those can be fixed.

if c is a variable, it will be parsed as object literal, otherwise it is considered as scope and been parsed as expression block.

ex. var x = { a } will be parsed as var x = { a: a } var x = { a() } will be parsed as var x = a(), under current specs it would be syntax error.

You missed the original proposal here. Your examples should be this (with the preceding =):

var x = = { a }
var x = = { a() }

In this case, this proposal should not cause any confusion IMO.

To clarify, I'm mentioning parser ambiguity, not visual (which does exist to some extent).

# Yongxu Ren (8 years ago)

Isiah, In your case, if we do

var x = = { a }

there isn't much difference from the do expression, actually, it might be worse since it looks confusing. if it can not be omitted, I'd rather stay with do.

The intent for this proposal is to allow writing better functional code in javascript. IMO, the do expression is a good start, but I think using = (and other operators) is a more elegant since it can be omitted.

Actually, I think I have a better idea to put it together:

1. besides defining a function, if the block can be legally be replaced by an expression, while otherwise it would cause parsing error, convert it to expression block

2. if the case is ambiguous or it is been used in function declaration, adding = (actually, using do here isn't a bad idea either, but can be quite ugly for defining function) will enforce block to be parsed as expression

The goal is to make javascript more functional friendly.

# Isiah Meadows (8 years ago)

I like the idea of expressions over statements (it's actually my preference), but not at the cost of breaking everything (feel free to fork Acorn/Escodegen and create your own transpiled JS variant - their licenses permit it), so my support of your particular idea is pretty much nil, at least in the JavaScript standards.

# JongChan Choi (8 years ago)

there isn't much difference from the do expression, actually, it might be worse since it looks confusing. if it can not be omitted, I'd rather stay with do.

I thought omitting additional brackets(var foo = = if (cond) { bar } else { baz }) was most sweet spot in this proposal than do expressions. what do you think about var foo = do if (cond) { bar } else { baz };?

# Isiah Meadows (8 years ago)

Beat you to it by about a year ;-)

esdiscuss.org/topic/generalize-do-expressions-to-statements-in-general

And to be quite honest, I did find it got some interest from TC39, but it was one of them IIRC that pointed out the ambiguity with do { ... } while (...), in which the fix would require no line terminator between the } and while, but it wasn't particularly elegant. Keep in mind they are interested (V8 implements the original proposal behind a flag FWIW), but it's the parsing difficulty that's the blocker. I'm currently writing up an alternative strawman right now that would probably end up a little more intuitive. (Loops will trip up way too many people with the current semantics, for example.)

On Tue, Nov 1, 2016, 09:21 JongChan Choi <jong at chan.moe> wrote:

there isn't much difference from the do expression, actually, it might

be worse since it looks confusing. if it can not be omitted, I'd rather stay with do.

I thought omitting additional brackets(var foo = = if (cond) { bar } else { baz }) was most sweet spot in this proposal than do expressions. what do you think about var foo = do if (cond) { bar } else { baz };?

    1. 1., 오후 4:10, Yongxu Ren <renyongxu at gmail.com> 작성:

Isiah, In your case, if we do

var x = = { a }

there isn't much difference from the do expression, actually, it might

be worse since it looks confusing. if it can not be omitted, I'd rather stay with do.

The intent for this proposal is to allow writing better functional code

in javascript. IMO, the do expression is a good start, but I think using = (and other operators) is a more elegant since it can be omitted.

Actually, I think I have a better idea to put it together:

*1. besides defining a function, if the block can be legally be replaced

by an expression, while otherwise it would cause parsing error, convert it to expression block*

*2. if the case is ambiguous or it is been used in function declaration,

adding = (actually, using do here isn't a bad idea either, but can be quite ugly for defining function) will enforce block to be parsed as expression*

# Cyril Auburtin (8 years ago)

Do expressions seems like another thing like => ({ }) to fix the mess with curly braces (used for expressions or objects litterals)

var f = x => ({ foo: 1}); // need () there, but we get used to it.

var f = { x: {foo: 1} }; // no need for ()

But do expressions seems the less bad way (= would be confusing), to solve things like format1 below

format1({
  html() {   // unecessary function to wrap expressions
    doSomething(...);
    res.send('..')
  },
  json() {
    //...
  },
})
format2({
  html: (()=>{   // bit ugly with iifes
    doSomething(...);
    res.send('..')
  })()
})
format2({
  html: do { // do expressions proposal
    doSomething(...);
    res.send('..')
  }
})
format2({    // if you have just one statement, is it stricly equivalent to do { res.send('...') } ?
  html: res.send('..')
})

2016-11-01 16:46 GMT+01:00 Isiah Meadows <isiahmeadows at gmail.com>: