an operator for ignoring any exceptions

# Sheng TIAN (7 years ago)

Is there any proposal for an one unary operator for ignoring any exceptions.

(I have not search out any related threads. But it is useful IMO, so I'm wondering if this had been discussed.)

For example, we may introduce an unary operator called try which

  1. calculate the operand first
  2. if it not throw, return as is
  3. otherwise return undefined

This operator may be used when exceptions should always be ignored.

Example:

let resp;
try {
  resp = JSON.parse(xhr.responseText);
} catch (_ignore) { /* do nothing here */ }

may be simplified to:

const resp = try JSON.parse(xhr.responseText);

Another Example:

var age = user && user.age;

to:

var age = try user.age;

(Note, in such case, if operand is start with curly braces "{", it must be wrapped in parentheses "()".)

# kai zhu (7 years ago)

-1 in my real-world experience, JSON.parse and nodejs fs.readFileSync are the only 2 common use-cases that would benefit from this. its more practical to use helper-functions for those 2 use-cases rather than change the javascript language yet again (besides, returning an empty string is commonly more useful for me than returning undefined for failed fs.readFileSync).

this is also a likely footgun that would get abused by novice programmers for many inappropriate use-cases.

# Frederick Stark (7 years ago)

Having recently inherited a codebase which silently consumes errors in many places (using try/catch, Promises that don't reject - just stall, and promise.catch noops), I can imagine these getting used terribly.

At least with the current operators, there's an expectation in the syntax that you will handle the error, and you have to make the conscious decision to ignore the error. Introducing an operator that does it for you implies to novice programmers that it's an okay thing to do.

The amount of extra code required to ignore the errors is not very onerous, and if you need it frequently, you can always put it in a wrapper function.

-- Fred Stark m: 0468 828 420 | e: coagmano at gmail.com id: keybase.io/coagmano | pgp: 43B91213.asc I acknowledge the Gadigal people of the Eora Nation, who are the traditional owners of the land on which I work and live.

# Naveen Chawla (7 years ago)

Yes I wouldn't remove the "catch" feature. However the idea of a "ternary" like operator expression for try catch and finally might be interesting, e.g.:

const resp = try? JSON.parse(xhr.responseText) catch(e): 'Error:
'+e.message finally: console.log('done!');
# Siegfried Ehret (7 years ago)

Hello,

This proposal approach the same subject: michaelficarra/optional-catch-binding-proposal (stage 3) Not handling errors is a bad practice. I join Kai Zhu and Frederick Stark here, this should not be a language feature.

-- Siegfried Ehret siegfried at ehret.me

# T.J. Crowder (7 years ago)

On Wed, Aug 2, 2017 at 4:58 AM, Sheng TIAN <llltgd at gmail.com> wrote:

Is there any proposal for an one unary operator for ignoring any exceptions.

(I have not search out any related threads. But it is useful IMO, so I'm wondering if this had been discussed.)

In general, a thorough search before posting is your best course.

To the idea: I join the chorus saying that making it easy to ignore errors is generally not a good idea. And reusing try for something that suppresses exceptions implicitly is separately not a good idea in my view.

However, the concept of a try-catch expression may have some value, just as throw expressions may have some value. For instance, your JSON example:

const resp = try JSON.parse(xhr.responseText) catch undefined;

There I'm incorporating the idea of catch with an optional binding. More on that in a moment.

E.g.:

Evaluation:

TryCatchExpression :
    try AssignmentExpression catch AssignmentExpression
  1. Let ref be the result of evaluating the first AssignmentExpression

  2. If ref is an abrupt completion:

    a. Let ref be the result of evaluating the second AssignmentExpression

    b. ReturnIfAbrupt(ref)

  3. Let val be ! GetValue(ref)

  4. Return val

...or something along those lines.

(I'm not immediately seeing a role for finally in such a thing.)

This would apply to various expression contexts, such as a concise arrow function body:

doRequest().then(text => try JSON.parse(text) catch undefined).then//...

as opposed to (still incorporating optional catch bindings):

doRequest().then(text => { try { return JSON.parse(text); } catch { return

undefined; } }).then//...

or the more concise but less clear:

doRequest().then(text => { try { return JSON.parse(text); } catch { }
}).then//...

If you want a catch binding, such as this...probably less-than-ideal example:

const resp = try JSON.parse(xhr.responseText) catch (error) ({error});

...I suppose the scope of the binding could be limited to the catch expression (just as the scope of the parameters to a concise arrow function are scoped to that function's expression body; "just" without the function boundary).

If a concise "use undefined on error" were considered a good idea, the catch expression could default to undefined if not given (not entirely unlike falling off the end of a function):

const resp = try JSON.parse(xhr.responseText) catch;

Personally, I prefer explicit to implicit and wouldn't want an implied undefined.

All of that said, I wonder if the gains are really worth the complexity of syntax. But in a world where throw expressions and do expressions are on the table (to varying degrees), a try-catch expression may be of interest, particularly in FP.

-- T.J. Crowder

# Tab Atkins Jr. (7 years ago)

On Wed, Aug 2, 2017 at 3:45 AM, T.J. Crowder <tj.crowder at farsightsoftware.com> wrote:

On Wed, Aug 2, 2017 at 4:58 AM, Sheng TIAN <llltgd at gmail.com> wrote:

Is there any proposal for an one unary operator for ignoring any exceptions.

(I have not search out any related threads. But it is useful IMO, so I'm wondering if this had been discussed.)

In general, a thorough search before posting is your best course.

To the idea: I join the chorus saying that making it easy to ignore errors is generally not a good idea. And reusing try for something that suppresses exceptions implicitly is separately not a good idea in my view.

Agree. Note that the similar operator (try!(...)) in Rust does not suppress errors, but rather just simplifies handling of the error (in Rust, expressed using a Result object); if an error is returned it immediately returns from the outer function with the Result object; otherwise it evaluates to the (unwrapped from the Result object) success value. This is closer to the try expression you bring up, just with some slightly more opinionated handling.

# Hikaru Nakashima (7 years ago)

I think this idea is useful in async function.

For exsample, we write codes as below, when we use fetch() in async function.


let res, text

try {
    res = await fetch( url )
} catch ( err ) { console.log( 'network error' ) }

if ( ! res.ok ) console.log( 'server error' )
else text = await res.text( )


or


let res, text

res = await fetch( url ).catch( err => null )

if ( ! res ) console.log( 'network error' )

else if ( ! res.ok ) console.log( 'server error' )
else text = await res.text( )


but, we can write as below if we use this proposal.


let res, text

res = try await fetch( url )
if ( ! res ) console.log( 'network error' )

else if ( ! res.ok ) console.log( 'server error' )
else text = await res.text( )

or do we need another syntax like "await?" ?

# Viktor Kronvall (7 years ago)

I think this proposal has the risk of swallowing too many errors making code hard to debug and would therefore suggest this shouldn’t be added to the language. Silent errors are hard to find the origin and cause for especially if you throw away the error message.

This might be slightly off topic but, I think we should instead wait for proper pattern matching and include a Result type similar to Scala Option or Haskell Either that is falsy in the Left error case (containing the error message) and truthy otherwise. 2017年8月11日(金) 10:17 Hikaru Nakashima <oao.hikaru.oao at gmail.com>:

# Hikaru Nakashima (7 years ago)

I have two thinkings about risk of this idea.

First, I think this syntax is almost same risk as try-catch syntax, because try-catch syntax is often used for just swallowing errors and it will be making hard to debug. Rather, this might be better because the target of syntax is partial. This is like the techniques to convert null or undefined to basic value of types we hoped.

Second, how about make the debugger tells us silent errors like uncaught promise error. I think we would not mind that all silent errors appear to console, because they was supposed to be appear if unless this syntax. For above fetch example, we would want to know errors even if we want to silent it in codes.

# Sebastian Malton (7 years ago)

An HTML attachment was scrubbed... URL: esdiscuss/attachments/20170811/2cd4579b/attachment

# Michał Wadas (7 years ago)

It's extremely unlikely that new syntax will be introduced to replace one line helper function. Especially after experiences of PHP where swallow-error operator is a source of eternal torment.

swallowException = fn => Promise.resolve().then(fn).catch(()=>null)

# Jordan Harband (7 years ago)
# Hikaru Nakashima (7 years ago)

Mr. Wadas, I think whether it can replace by one line helper function is not much relationship, because Optional Chaining, Throw expressions, or many proposals can replace so too.

In addition, there is optional catch binding proposal, and this idea is less dangerous. Rather, this idea looks natural, because foo = try bar is looks like foo = do { try { bar } } .

# T.J. Crowder (7 years ago)

On Sat, Aug 12, 2017 at 7:14 AM, Hikaru Nakashima <oao.hikaru.oao at gmail.com> wrote:

In addition, there is optional catch binding proposal, and this idea is less dangerous. Rather, this idea looks natural, because foo = try bar is looks like foo = do { try { bar } } .

I think you're misunderstanding the optional catch binding proposal. It does not make try { something } valid. It makes try { something } catch { } valid. It's for all those times you don't need the exception, so the binding (the (e) part of catch (e)) is made optional.

If I'm wrong about your misunderstanding the proposal, my apologies; if so, what's dangerous about optional catch bindings?

Making catch optional would indeed, in my view, be dangerous, which is why I don't like the suggestion that's the topic of this thread. If you're going to ignore exceptions on a block, for which, yes, there are valid use cases, I much prefer that it be explicit.

-- T.J. Crowder

# Hikaru Nakashima (7 years ago)

I'm sorry, I was misunderstanding and confused, and thank you to teach me.

I want you to tell me why dangerous to omit catch. Is that because, people abuse the syntax ?

# T.J. Crowder (7 years ago)

On Sun, Aug 13, 2017 at 6:21 PM, Hikaru Nakashima <oao.hikaru.oao at gmail.com>

wrote:

I want you to tell me why dangerous to omit catch. Is that because, people abuse the syntax ?

"Dangerous" is a bit over-the-top, I was just reusing the word for parallel construction.

But I prefer explicit to implicit. This:

try { something; } catch { }

isn't that much longer than this:

try { something; }

...and for me, having that glaring empty block there saying "You really should do something here" is a good thing. :-)

-- T.J. Crowder

# Claude Pache (7 years ago)

Note that, in a try/catch/finally construct, you can already omit the catch clause if there is a finally clause. The effect, of course, is not to swallow the exception, but, on the contrary, to propagate it as if there was catch (e) { throw e }. (The useful part of such a construct is the finally clause.)

Also, in languages and dialects supporting conditional catch clauses, if the thrown exception does not match the condition of any catch clause, it is propagated.

So, the rule is: If there a matching catch clause, the exception is handled by it; otherwise, it is propagated. Reversing that rule (“propagated” → “not propagated”) is very dubious, to start (regardless of any other consideration).