-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Discussion: try
expression without catch
for inline use
#220
Comments
I'm sure this change will push people not into the pit of success, but into the cliffs of insanity. There's a reason why "On Error Resume Next" is the most offensive thing you can say to a VB programmer. |
@orthoxerox Nevertheless I understand your concerns, but I don't think that it will have too much impact. As with so many company conventions, there could be one that disallows usage of a try expression when not thorougly documented why it is used. For all others this would much probably be an ease! |
And by the way, actually it wouldn't be much different than using |
public static StreamReader TryNewStreamReader(string filePath)
{
try
{
return new StreamReader("C:\nonexistingfile.txt");
}
catch { }
return null;
}
...
var textStream = TryNewStreamReader("C:\nonexistingfile.txt");
if (textStream != null) ProcessFile(textStream);
GoOnWithOtherThings(); |
@DavidArno are you kidding me....?!?!?!?! 😕 var textStream = TryNewStreamReader("C:\nonexistingfile.txt");
// compare to
// var textSTream = try new StreamReader("C:\nonexistingfile.txt");
if (textStream != null) ProcessFile(textStream);
GoOnWithOtherThings(); The complete "TryNewStreamReader()" is so something of spoiling overhead! And besides you used an empty catch block in it. Exactly what this proposal is going to avoid! |
How do you propose avoiding the empty catch block? I simply copied your example code. |
That's the whole point of this proposal. var textStream = try new StreamReader("C:\nonexistingfile.txt"); is all that is needed. It is semantically equivalent to try {
var textStream = new StreamReader("C:\nonexistingfile.txt");
}
catch { } but without the boilerplate around it. |
|
@DavidArno I like to look at things without any prejudice or preassumptions and from different angles from time to time. During my early days I have teached beginner programming classes. That was around the time of C# 1.0 (the classes were for Pascal though). That again teached me to "dive into the thread of thoughts" of others, to see where their problem of understanding is or why they wrote the code as it was when it came to debugging. From a theoretical and operational point of view, I totally agree, that every exception should be caught and thought of wisely. From a practical and more humal like POV in my eyes it isn't that bad to omit exceptions. It's due to the vast number of exceptions that could throw anytime. Non-experienced programmers could easily be discouraged, because it takes too much time to respect them here and there. And all this When you - without prejudice! - look at some code ( I don't mean enterprise class code, just everyday laying around code ) you will most certainly find quite a lot of By the way, in this forum are mainly enthusiasts who might have a more professional look on things. Please respect that there are others on this planet who love C# and program for fun, but find this or that annoying and improvable. (And professionals will probably ignore features like this proposed one anyway - and if not, then there might be a use for it, indeed 😉 ) |
I just don't think that a language should help programmers to write bad code but guide them to write proper code. And, in my opinion, a catch all clause is always dangerous and therefore should not be something that the compiler should insert automatically. |
@FredyFerrari By now the language encourages to write catch all clauses, that also look ugly, leads to additional braced blocks and indention: try {
var textStream = new StreamReader("C:\nonexistingfile.txt");
}
catch { } When do I write that kind of code? => When I'm too lazy to catch the exception right now, because I concentrate on the actual work of the module. Maybe I come back later to care about exceptions. ( 'I' is not ment personally ) So all I have done is to insert that Inlining that very The IDE can always transform it to a full try-catch-block (e.g. one-way only) and help me finding inlined |
But allowing this would make people think, |
@FredyFerrari var textStream = try new StreamReader("C:\nonexistingfile.txt"); looks better than var textStream = try { new StreamReader("C:\nonexistingfile.txt"); } catch { } ? I myself do not like the extensive use of curly braces, e.g. like here (besides it wouldn't compile). |
Point of the Tester-Doer pattern is to avoid the exception not to swallow it, so it's very different. |
Well, how about this: var textStream = (
(Func<StreamReader>)
delegate () {
try { return new StreamReader("C:\nonexistingfile.txt"); } catch { return null; }
})(); vs. var textStream = try new StreamReader("C:\nonexistingfile.txt"); 😂 😂 😂 😂 |
You are right, and it's a historic flaw in the language. It's easier to write a bad catch-all than it is to eg write: try
{
var x = new StreamReader("C:\nonexistingfile.txt");
...
}
catch (Exception e) when (e is ArgumentException ||
e is FileNotFoundException ||
e is DirectoryNotFoundException ||
e is IOException) {} There's nothing we can do about that historic problem. However, making it even easier to write catch-all's, as per this proposal, is just digging that "pit of failure" hole even deeper. |
@lachbaer There! you even get the PHP syntax you always wanted.
All you need to do is put |
Exception handling can be more performant than test-doing And image the code on that page with the proposed |
I would rather support a try-catch expression, which returns a value if no exception, but on exception executes the catch block and do not proceed after that. In void returning methods, it just returns after executing catch block. For other methods, it's an error not returning within the catch block. Similar to proposed try {
var textStream = new StreamReader("C:\nonexistingfile.txt");
ProcessFile(textStream);
}
catch (Exception e) { Logger.Log(e); }
GoOnWithOtherThings(); becomes var textStream = try new StreamReader("C:\nonexistingfile.txt")
catch (Exception e) { Logger.Log(e); }
// textStream is definitely defined at this point
// and no exception thrown in the try expression evaluation
ProcessFile(textStream);
// In case of exceptions, this method will not be executed.
GoOnWithOtherThings(); But if you want to swallow, you have to do it explicitly- var textStream = try new StreamReader("C:\nonexistingfile.txt") catch { return null; }
ProcessFile(textStream); |
@gulshan You should make a new proposal about it as it is divergent. |
I completely disagree! As you say, it is already there. I think I get you right if you would have it closed completely, but that will most likely never be the case. Please think again about what I wrote concerning the help of code analyzers. When people start using a try statement instead of a catch-all block these occurences could be easily highlighted and complained by an analyzer. They will write those catch-all's anyway! So, in this view it even encourages to inspect those places and to refactor to meaningful catches. It also enhances writability, because by using the try statement you can concentrate on the main issue, but also marking places that you gonna have to inspect later. |
var textStream = try new StreamReader("C:\nonexistingfile.txt") catch { return null; } Actually, I think the main purpose for my suggestion of a try-statement is for assignments. So, I could go with his. However, As this is for returning it could be var textStream = try new StreamReader("C:\nonexistingfile.txt")
catch => null; @gulshan -- Addendum -- var textStream = try => new StreamReader("C:\nonexistingfile.txt");
catch { /* ordinary catch block */ }; Or if you prefer a no-catch one-liner var textStream = try => new StreamReader("C:\nonexistingfile.txt"); catch {} would translate to StreamReader textStream = null;
try {
textStream = new StreamReader("C:\nonexistingfile.txt");
}
catch { /* ordinary catch block */ }; In case you just need var textStream = ( try => new StreamReader("C:\nonexistingfile.txt"); catch { } )
?? new StreamReader("C:\existingfile.txt"); |
@DavidArno |
@DavidArno Besides a "try-catch-expression" goes far beyond that one written function. |
-1. I have witnessed first-hand the horrors of catch-all blocks. Unless you are a message loop or threading framework, you have no business swallowing exceptions that don't belong to you. (And if you are, you re-throw them.) It's both dangerous- by far the safest action for any business is for the program to immediately crash on an unexpected exception rather than run in an unknown state- and frustrating because other code swallowing makes it impossible for you to handle the exception higher up the call stack, even if the exception is your responsibility to know about and handle! When this happens in real life, you gain more perspective than simply the fallacy that it's okay to swallow all exceptions. |
On Error Resume Next |
@vbcodec The intent is to reduce boilerplate code, behind the scenes exceptions are still caught if they occur.
|
|
@CyrusNajmabadi var v = try DoSomething() match (
case SomeType t: Something(),
case OtherType x: Whatever(),
catch (Exception e): AndSoOn());
// or (not my choice)
try var v = DoSomething() match ( ... ); So, a |
Not really, the syntax is invalid and can be compiled exactly to what you proposed in your post so it isn't ambiguous. |
Having used
These modifications would already pump up coding 😄 |
Two different ideas to this proposal can be seen here: var x = try CalculateInt() catch(Exception e) => 0;
Those two should be seperate proposals. |
Well, almost all languages have some version of inline try catch. Ruby especially is Brilliant with the "rescue" keyword. I'm right now trying to delete files which may or may not exists. I don't want to wrap in a try catch.. I would personally recommend a lambda expression like below: This allows the option to do more with the exception, or not if not needed. |
I would also propose two other try expressions: 2- if try(var i = Convert.ToInt32(o))
DoSomething(i);
else if try(var i = Convert.ToInt64(o))
DoSomething(i);
else if try(var i = Convert.ToIntDecimal(o))
DoSomething(i);
else if try(var i = Convert.ToDouble(o))
DoSomething(i); |
Why all the exception throwing? Just make use of pattern matching, nullable structs and the "try pattern": if (TryConvertToInt(o) is int i)
DoSomething(i);
else if (TryConvertToLong(o) is long l)
DoSomething(l);
else if (TryConvertToDecimal(o) is decimal d)
DoSomething(d);
else if (TryConvertToDouble(o) is double d2)
DoSomething(d2); This already works and doesn't require exception swallowing. |
using System;
using static Helpers;
public static class Helpers {
public static bool Try<T>(Func<T> f, out T result) {
try {
result = f();
return true;
}
catch (Exception) {
result = default;
return false;
}
}
}
static class Program {
static void Main() {
object o = null;
if (Try(() => Convert.ToInt32(o), out var result)) {
DoSomething(result);
}
}
} |
@HaloFour |
I like this syntax: var stream = new StreamReader("C:\nonexistingfile.txt") !! null; means StreamReader stream;
try
{
stream = new StreamReader("C:\nonexistingfile.txt");
}
catch
{
stream = null;
} see #3495 @HaloFour The under codes can change trycatch code to tranditional c-like code; var o = "12text";
var result = Convert.ToInt32(0) !! -1;
if (result != -1)
DoSomeThing(result); In some cases, exception has been abused in some language(maybe java), and so rust choose the other way. How to design a API when matching unexpected parameter? Throwing exception maybe is a lazy way. |
@surfsky GameObject gameObject;
var boolean = !!gameObject; // intentionally boolean |
@Thaina Are you sure? I test under codes in netcore console, and get failure: static void Main(string[] args)
{
var o = "hello world";
var b = !!o; // CS0023 C# Operator '!' cannot be applied to operand of type 'string'
} |
@Thaina |
@surfsky Yeah, what I try to tell is, while
Another possibility such as, there would be 3 state rotation of value. And some people use So as I said, it is already a valid syntax and some people might already use it for something we don't know of |
I'm in favor of this proposal, due to the following use case recently encountered by me that thence lands me here after searching: I tried to fetch a configuration value with fall backs at different stage. Now my code looks like this:
//you can see the logic is simple (just fall back cascadingly ) but the code obliterates that simpleness, whileas with the proposed syntax somewhere in this discussion, we can revert that simpleness. |
@wangyoutian this discussion is closed - if you read back through the threads you can see the compelling reasons why. It's worth pointing out that you can easily restructure the sample you gave to make it much easier to read (and to reduce the number of allocations as well), just by breaking out each branch as a local function with a well chosen name:
The names I chose for each function might not be the best, but I hope this illustrates my point. |
But I know what I am doing, that's why it's a non breaking change for me to opt in |
If something becomes enshrined in the C# language, that's an explicit endorsement that the approach is a good one. The language design team have been quiet explicit about this - if it's wordy and difficult to write atrocious code, that's a good thing. Making it easier is not desirable. |
Proposal:
try
expression withoutcatch
for inline useIntent
Sometimes it is not necessary to catch an exception, because you can either check side conditions or proceed though the expression is failed. In these cases it would be nice to skip the exception checking.
Example
In current code there would be something like
or even wrap it additionally with
This could be abbrevated and streamlined drastically with
The catching isn't necessary here, because a null-check (that should be done in
ProcessFile()
anyway) already cares about the failure. A completetry { } catch { }
is just unnecessary boilerplate.I guess that there are plenty of other useful scenarios where this would come in handy.
Other languages
PHP uses the
@
operator before an expression to suppress errors and warningsIn PHP
@
is used quite often to shorten things.Now, open for discussion... 😄
The text was updated successfully, but these errors were encountered: