an operator for ignoring any exceptions
-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.
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.
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!');
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
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
-
Let ref be the result of evaluating the first AssignmentExpression
-
If ref is an abrupt completion:
a. Let ref be the result of evaluating the second AssignmentExpression
b. ReturnIfAbrupt(ref)
-
Let val be ! GetValue(ref)
-
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
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.
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?" ?
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>:
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.
An HTML attachment was scrubbed... URL: esdiscuss/attachments/20170811/2cd4579b/attachment
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)
Relevant existing proposals:
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 } }
.
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, becausefoo = try bar
is looks likefoo = 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
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 ?
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
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).
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
whichThis operator may be used when exceptions should always be ignored.
Example:
may be simplified to:
Another Example:
to:
(Note, in such case, if operand is start with curly braces "{", it must be wrapped in parentheses "()".)