Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

A year back I dropped a proposal idea at the EcmaScript discussion list, I hope it get's picked up sometime.

My idea is that `let`, `var` and `const` return the value(s) being assigned. Basically I miss being able to declare variables in the assertion part of `if` blocks that are scoped only during the `if()` block existence (including `else` blocks).

Something along these lines:

    if( let row = await db.findOne() ) {
         // row available here
    }

    // row does not exist here
The current alternative is to declare the variable outside the `if()` block, but I believe that is inelegant and harder to read, and also requires you to start renaming variables (ie. row1, row2...) due them going over their intended scope.

As previous art, Golang's:

      if x:=foo(); x>50 {
        // x is here
      }
      else {
        // x is here too
      }
      
      // x is not scoped here
And Perl's

      if( ( my $x = foo() ) > 50 ) {
           print $x
      }


Also see assignment expressions recently adopted in python 3.8: https://www.python.org/dev/peps/pep-0572/


In Python things are a bit different because declarations and assignments are ambiguous.


They're not ambiguous, assignments are declarations unless the variable was pre-declared (via global or nonlocal).

Assignment was specifically made a statement to avoid the confusion / typo risks of `=` v `==`.


They are not ambiguous if you have the whole file in your head. This is why there are keywords like "global" & "nonlocal".


> They are not ambiguous if you have the whole file in your head.

They're not ambiguous period, python's `=` always performs a local declaration unless overridden via the keywords you mentioned.

> This is why there are keywords like "global" & "nonlocal".

It's the exact opposite of your statement: `global` and `nonlocal` indicate non-local bindings, because by default all bindings are local and you do not need to have "the whole file in your head".


Also its addition to Python was controversial, to say the least. (I have been enjoying using it, however)


I know this doesn't match up entirely with what you want syntax wise, but the following works and I consider it quite elegant.

  {
    let row;
    if (row = await db.findOne()) {
      //
    }
    else {
      //
    }
  }


It's not the same. For instance, you could not use a `const` variable.

Also having "phantom" scope blocks get very nasty to read once you have more involved logic, as the block itself has no implied meaning and the programmer has to walk a few lines into it to get what's going on.


You could always make it a labelled block statement !


Seems like pretty trivial bikeshedding. How about just:

    const user = await db.findOne()
    if (user) ... else ...
Typescript can even narrow the type to null vs. User in each branch block.


Would the else branch trigger on a falsy value, or on an exception? It's a bit confusing, as it looks like it would handle exceptions on the else branch, even though we know we have to wrap await in try/catch for that.

Other than saving a few characters (the variable name), I don't see any benefit of this, while it makes code harder to read.

Too bad the `with` [0] keyword has been reserved for crap, it sounds nice (not for this, but maybe for something else).

>> and also requires you to start renaming variables (ie. row1, row2...) due them going over their intended scope

Variable shadowing [1] is a really bad practice that makes it hard for people to collaborate and keep the code sane. Bad habits are not a reason for language changes.

[0] - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

[1] - https://en.wikipedia.org/wiki/Variable_shadowing


You can also declare variables in conditional statements in C/C++ like https://godbolt.org/z/h0BR8K

  int foo(int);
  int bar(int x) {
    if (int y = foo(x)) return 0;
    return x;
  }


Nice. I like use of the let/var/const keyword to disambiguate from the accidental `if (x = y)` when intending to use `==`.


Only helps with const. Better use linting to avoid such issues.


> Only helps with const.

Can you elaborate?


If the `x` in the example was a const, it would throw an error because the code attempts to assign the value of `y` to `x`. You cannot assign a new value to a const.


What I'm saying is that you wouldn't accidentally type `let x = y` when you meant to type `x == y`


This has been discussed a few times on IRC, but no one has made a proposal yet afaik.


FWIW Swift lets you do this, and it's great. Guard statements even better.


You can also do this in Ruby, though the scope is different.


In my opinion this is a terrible idea, since it's very easy (I do it all the time) to accidentally write `if (foo = bar)` instead of `if (foo == bar)`. If that were valid syntax it would be a huge footgun. I'd be onboard with it if it required a different syntax.


I'm down if you require a let/var/const in front of it:

    if (foo = bar()) { // syntax error!
    }

    if (let foo = bar()) { // works fine
    }

    if (const foo = bar()) { // also works fine
    }

    if (var foo = bar()) { // also also works fine
    }


> if (foo = bar()) { // syntax error!

That's already an error in strict mode (which would presumably be on for anyone writing bleeding-edge JS).


It's only an error in strict mode if there's no variable in scope named foo.


And what if foo had already been defined in the scope?


The new one shadows it.


Local scope might not be what the programmer wants, though, depending on circumstance. Pseudocode:

  i = 3;
  foo = \0;

  while ( i-- ) {
      if ( foo = resultFromFooApi() ) {
          break;
      }
      sleep 1;
  }

  return foo;


But JS already allows that.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: