Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic do expressions if expression starts with if, for, switch, try etc. #9

Closed
kasperpeulen opened this issue Oct 11, 2017 · 12 comments

Comments

@kasperpeulen
Copy link

kasperpeulen commented Oct 11, 2017

I was playing with this plugin a bit, and this is very related to #7, I don't like excessive indentation for a simple if else statement in JSX. I use prettier, and maybe there could be something changed there as well, but look at this. I have a button here:

<div className="col">
  <button className="btn btn-info btn-lg" onClick={this.endTimer}>
    End timer
   </button>
<div>

Now I realise, that, before I end the timer, I need to check if the timer is started. So I use an if else construct:

<div className="col">
  {
    do {
      if (timer == null) {
        <button className="btn btn-info btn-lg" onClick={this.startTimer}>
          Start Timer
        </button>;
      } else {
        <button className="btn btn-danger btn-lg" onClick={this.endTimer}>
          End Timer
        </button>;
      }
    }
  }
</div>

Suddenly, the button is 6 spaces more indented! And a lot of more extra visual noise. Now since keywords like if, switch, for, try can't be used in an expression context, can't we automatically (behind the scenes), make a do expression construction of this if we encounter such keywords in a expression context. What I mean, could we allow to write the above like this:

<div className="col">
  {if (timer == null) {
    <button className="btn btn-info btn-lg" onClick={this.startTimer}>
      Start Timer
    </button>;
  } else {
    <button className="btn btn-danger btn-lg" onClick={this.endTimer}>
      End Timer
    </button>;
  }}
</div>
@claudepache
Copy link

I think it should be considered provided that braces are mandatory, i.e.

var a = while (foo) { bar; };

and not:

var a = while (foo) bar;; 

@tasogare3710
Copy link

tasogare3710 commented Nov 19, 2017

What happened to *?

I have a question. Does an implicit do expression require * only when an explicit do expression returns a generators?
Or is it always * necessary for an implicit do expression?

@RaoulSchaffranek
Copy link

RaoulSchaffranek commented Dec 9, 2017

@claudepache what is the rationale behind making curly-braces mandatory? Wouldn't this break with existing JavaScript syntax for statements, which let the programmer omit curly-braces in case of single-statement conditional-branches and loop-bodies? I recognize that most coding-styleguides and many developers consider curly-braces and semicolons good practice, however, i don't think the standard should be opinionated about a specific coding-style, if this means a break with the rest of the grammar.

@ljharb
Copy link
Member

ljharb commented Dec 9, 2017

@RaoulSchaffranek that's possible for if etc because they're statement blocks - they don't produce a value. do expressions produce a value, which makes them expressions. Also, consider non-arrow function bodies, which have always forced you to have curly braces - there's just not a convention in the language that consistently lets you omit them across constructs.

@pitaj
Copy link

pitaj commented Dec 9, 2017

I'll give you my rational. This proposal essentially provides "blocks that return a value". Requiring curly braces for if etc simplifies parsing and makes the styles of a "block that returns a value" consistent. If it starts with a keyword and has curly braces, then it's a block that returns a value. (with some exceptions, namely loops)

@RaoulSchaffranek
Copy link

I didn't think of it before @ljharb mentioned it, but i didn't mean to make curly-braces optional in all cases, in particular not for function-declarations and -expressions. On the other hand, they shouldn't be mandatory where the linked statement has optional curly braces. Ideally, the rules for curly-braces should line-up for abbreviated do-expressions and their corresponding statements. For example, if (true) 1 else 0 is a valid statement and following my logic there should be a corresponding do-expression if (true) 1 else 0 which desugars to do { if (true) 1 else 0 }. The most common use-case for left-out curly braces is seldom recognized as one: else if-branches. It would be awkward to have to write something like:

<div>
    {if (x > 0) {
        'x is positive'
    } else {
        if (x < 0) {
            'x is negative'
        } else {
            'x is zero' 
        }
    }}
</div>

Instead of the familiar:

<div>
    {if (x > 0) {
        'x is positive'
    } else if (x < 0) {
        'x is negative'
    } else {
        'x is zero' 
    }}
</div>

But then it is only consequent to allow the even shorter variant:

<div>
    {if (x > 0)     'x is positive'
    else if (x < 0) 'x is negative'
    else            'x is zero'}
</div>

@claudepache
Copy link

claudepache commented Dec 10, 2017

@RaoulSchaffranek

@claudepache what is the rationale behind making curly-braces mandatory?

My rationale was that, in absence of braces, you would have required semicolons in the middle of an expression, that would cause confusion. For instance, the following is a syntax error:

if (true) 1 else 0 // syntax error: missing semicolon after 1

You have to write:

if (true) 1; else 0;

which is acceptable for if-as-statement, but becomes confusing for if-as-expression:

const a = if (true) 1; else 0;; // yes, two semicolons

But if you are interested to use expressions rather than statements in the branches of the if-expression (thus not needing semicolons), you have the already-existing ? : operator:

<div>
    { x > 0 ?     'x is positive' 
      : x < 0 ?   'x is negative' 
      :           'x is zero'
    }
</div>

@claudepache
Copy link

claudepache commented Dec 10, 2017

@RaoulSchaffranek Also:

There is ASI, a feature that personally I use liberally, and which allowing you to “forget” semicolons. But... an example is worth thousand words.

A programmer writing consciously their semicolons:

const a = if (true) 1;
['foo', 'bar'].forEach(f);

Another programmer relying on ASI for inserting for them, but carefully adding them manually before statements beginning with dangerous characters:

const a = if (true) 1
;['foo', 'bar'].forEach(f)

Both are wrong, because both programs are equivalent to:

const a = (if (true) 1; else 0;)['foo', 'bar'].forEach(f);

@rosyatrandom
Copy link

rosyatrandom commented Feb 27, 2018

What would everyone make of formalising this with the following syntax: do-[x], where [x] is any of the applicable statements, try, if, switch, for. etc.? That should ease any burden on the parser to handle the code, and keep the clarity and concision we're going for.

Here's an example prompted by https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function. The motivation was simple: I hate using lets where a const should be possible.

// original 
async function getProcessedData(url) {
  let v;
  try {
    v = await downloadData(url); 
  } catch(e) {
    v = await downloadFallbackData(url);
  }
  return processDataInWorker(v);
}

// proposed:
async function getProcessedData(url) {
  const v = do-try {
      await downloadData(url); 
    } catch(e) {
      await downloadFallbackData(url);
    }
  return processDataInWorker(v);
}

// variants:
// await do/do-[x] -- allows implicit await from last statement of blocks
// whitespace allowed between do- and [x] -- allows for nicer indentation below
async function getProcessedData(url) {
  const v = await do-
    try { downloadData(url); }
    catch(e) { downloadFallbackData(url); }

  return processDataInWorker(v);
}

@pitaj
Copy link

pitaj commented Feb 27, 2018

I'd prefer if the do weren't necessary, but otherwise I like the idea of using do without a block to enable using any statement as an expression.

I'd prefer do [[Statement]] as opposed to do-[[Statement]] though.

@peisenmann
Copy link

It's irked me for quite a while that if and switch aren't expressions in JavaScript like they are in many other languages. The ternary is simply not sufficient to handle more than basic logic, but using statements is an extra burden in many cases (like the aforementioned JSX).

I see the issue in @claudepache 's comment about the ASI yielding the wrong results in that specific edge case, but I would take the double semicolon solution above the rest of the verbosity being suggested. Hyphenating and introducing more keywords just adds noise to the language, imho.

@bakkot
Copy link
Collaborator

bakkot commented Jan 30, 2021

In the interests of consolidating discussion, I'm going to close this issue in favor of #39, which is the same proposal but has more discussion. Please see my most recent comment there, in particular.

@bakkot bakkot closed this as completed Jan 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants