commondream
28d ago
23
14
zarzavat
It seems that the proposal itself has given up on the syntax in the article and will be proposing try expressions instead. The ?= syntax would never fly given that there's already a ??= operator that does something else.

Given that the (much simpler) throw expressions have been stuck in bureaucratic hell for 7 years, I look forward to seeing try expressions some time around the heat death of the universe.

spankalee
Since the proposal is moving to try expressions, my main criticism there is that I don't usually just want the error as a value, as then I still need to check it and write a branch to handle the error case. It's nice that I could use const on the value variable instead of let, but that's such a small gain.

What I really want for the expression to return the value, but give a branch for the error case:

    // We still get a catch block to handle errors in
    const value = try foo() catch (e) {
      throw new MyError('Error trying to foo');
    };
Otherwise we have to write this to handle the error:

    const [value, error] = try foo();

    if (error) {
      throw new MyError('Error trying to foo');
    }
And it's far to easy to forget the error handling code altogether, resulting in silent failures.

edit: removed a brain-fart on a case that's already handled by JS :O

spankalee
The real safe assignment that I want to see is for optional chaining to be valid in LHS of assignments:

    foo?.bar = 42;
This would not perform the assignment if an optionally chained value was nullish. It downlevels to

    foo == null ? undefined : foo.bar = 42;
Given that the assignment is a SyntaxError now, this should be possible.
Animats
It's syntactic sugar for try/catch blocks. No new functionality.

Try/catch and exceptions seem to be tough for programmers to handle. You have to have disciplined unwinding for exception propagation to work well when an unwind goes through multiple calls.

Rust's rather simple "?" operator, which I once thought was underpowered, seems to be a workable solution. It's just syntactic sugar for return on error, but because there's a standard error trait, that usually works out well.

The lesson from this is to get your error objects right early in the history of a language, because you can't retrofit them. Once you have that right, how to report errors becomes sane, and the mechanism becomes less important.

recursive
I don't think we'll ever see this. At least I hope we won't. Even specifying its behavior seems to be a nightmare. And you can basically just write it yourself.

    [val, err] ?= maybeThrow(); // instead of this
    [val, err] = wrapErr(maybeThrow); // you can write wrapErr yourself and use it forever
    [val, err] = wrapErr(maybeThrow, arg1, arg2); // you can even provide args
khffaydfsjd
This may be unorthodox for JS, but I treat exceptions like panics and use error values if I care about them. This also gives me type checking in TypeScript.
brundolf
This would make certain things more convenient, but wouldn't be very versatile and would feel terrible in terms of overall language semantics

Try expressions (mentioned in other comments) seem significantly better, but still feel like they're trying to tack on something that fits awkwardly into the original language design (though that's kind of the history of JavaScript)

Anyway, I'd use those all the time if they landed

timwis
Hah, thought this looked familiar… I had a similar idea back in 2017 and published a little 5-line library to get this type of syntax ([err, result] for async): https://github.com/timwis/eres
hyperhello
Is try really meant for casual flow control, or should it be last ditch error recovery? ?: makes sense, forEach() makes sense, but not every kind of block needs a backup syntax.
chipsrafferty
"To access errorMsg outside of the try/catch block using const or let you have to define it outside of the block."

Just use var, then.