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

Proposal: try/catch expressions with lambda-like syntax #37304

Closed
Pxtl opened this issue Jul 17, 2019 · 3 comments
Closed

Proposal: try/catch expressions with lambda-like syntax #37304

Pxtl opened this issue Jul 17, 2019 · 3 comments

Comments

@Pxtl
Copy link

Pxtl commented Jul 17, 2019

Problem: try/catch is a statement, not an expression, which means you can't use it in contexts that need an expression. It's also tedious because it means variables that are loaded inside the "try" block must be pre-declared, which results in a lot of repeated type and variable names. This encourages large expansive try-blocks where all of the logic happens inside of the try, which is worse practice than small, specific catch blocks that only cover the expected site of the exception.

Obviously, we need a try/catch expression.

Previous proposals for try/catch expressions either encouraged empty catches(awful) or only allowed catching a single exception-type (bad) or failed to handle the ambiguity of multiple nested catches. Or used new non-idiomatic operators or misuse of existing symbols.

Instead, I'm suggesting a syntax that should be pretty idiomatic to C# 3.0 and later.

proposal

By toy example first:

var myValue = try => dict[key] catch((KeyNotFoundException ex) => null);

as you can see, slightly noisier than a normal Try-Catch, but still terse and clear, and leverages familiar Lambda syntax.

More elaborate example.

var responseCode = try => doStuff().ReponseCode catch(
    (HttpException ex) when (ex.Code < 500) => ex.Code, //just pass-through the response-code
    (HttpException ex) => { //for 500 and up errors, log the error before returning
           logger.Error(ex);
           return ex.Code;
    },
    (Exception ex) => {  //treat all other errors as 500s.
         logger.Error(ex);
         return 500;
    }
);

so you can see, the pattern is

try => try_expression catch(
    (exception_type_1 [exception_var_1_name]) [when exception_when_expression_1] => exception_expression_1, 
    (exception_type_2 [exception_var_2_name]) [when exception_when_expression_2] => exception_expression_2, 
     ...
    (exception_type_N [exception_var_N_name]) [when exception_when_expression_N] => exception_expression_N
)

where all of exception_expression_N must return a type that is or can be implicit cast into the return type of try_expression, or they must throw.

If an exception expression needs to be broken out into a multi-statement body, then the syntax already established for doing the same for lambdas is used.

Finally is not a thing, because it's really non-expressiony.

This also avoids the ambiguity problems - the lambda-arrows make it unambiguous compared to a normal try...catch (an existing try will never be followed by a lambda arrow). Because all the catch blocks are in a single catch( ... ) parens there is no ambiguity if tehre are multiple nested try => blocks about which catch corresponds to which try.

Using a parens to contain multiple (parameters) => expression, delimited with commas, is already idiomatic C# because it's commonly done in higher-order functions, such as LINQ expressions.

No existing try...catch features such as multiple catch-blocks, when-clauses, etc. are sacrificed other than "finally", and the empty catch{...} which can be emulated with (Exception) => null and should never be used any time ever anyways.

@RikkiGibson
Copy link
Contributor

RikkiGibson commented Jul 17, 2019

Please submit C# language feature proposals to https://github.com/dotnet/csharplang

@jnm2
Copy link
Contributor

jnm2 commented Jul 17, 2019

@Pxtl
Copy link
Author

Pxtl commented Jul 17, 2019

Sorry, I thought all issues related to this were already closed because of flaws in the proposal, couldn't find the open one. Added proposal as comment to the open one dotnet/csharplang/issues/980

@Pxtl Pxtl closed this as completed Jul 17, 2019
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

3 participants