4 ms·
The main downside of C# when compared to Java is its weaker exception handling, see here: https://mckoder.medium.com/the-achilles-heel-of-c-why-its-exception-ha
by breadwinner 2y ago
The main downside of C# when compared to Java is its weaker exception handling, see here: https://mckoder.medium.com/the-achilles-heel-of-c-why-its-exception-handling-falls-short-f7f932488aba https://mckoder.medium.com/the-achilles-heel-of-c-why-its-ex...
- Dwedit 2y agoIn earlier versions of C# (including .NET 3.5), Access Violations did not inherit from Exception, and could not be caught using "catch (Exception ex) { }" syntax. You had to use "catch { }" syntax instead.
- neonsunset 2y agoYou still cannot catch AccessViolationException, StackOverflowException or ExecutionEngineException. This is by design because each indicates catastrophic unrecoverable failure (you could have a couple of hand-wavy arguments about AVE dereferencing wrong address but, really, that indicates critical error in implementation or memory corruption still). You should never see any of these regardless. Aside from abusing stackalloc by passing a large number I guess.
- vips7L 2y agoI’m really passionate about exceptions and checked exceptions in general. Java really has done a disservice by not making it easy to uncheck checked exceptions. Much like rust I hope they offer some sort of ? operator in the future. This really is the main gripe with checked exceptions.
- breadwinner 2y ago> uncheck checked exceptions. What do you mean? if you add "throws Exception" to every method then you can defeat checked exceptions but please don't do this in production code
- vips7L 2y agoRight. What I mean is that when you can't handle an exception and you should rightfully become unchecked it's extremely verbose. For example if I'm reading a config file and I should rightfully panic and crash my program if that file doesn't exist: Config config; try { config = readConfig("/some/path/to/a/file/that/must/exist.txt") } catch (IOException ex) { throw new RuntimeException(ex); } doSomeStuffWith(config); Realistically situations like this should be: Config config = readConfig!!!("/some/path.txt"); // !!! being some operator that says "shut up compiler crash if this happens" doStuffWith(config); People do not like checked exceptions because they either need to check and colour the whole stack or write way too much code to panic.
- breadwinner 2y agoIt is not very common to run in to an error that should crash the application. If you have to write a bit of code to do that, in my opinion that's fine.
- vips7L 2y agoI'm just going to say that you're opinion is wrong. You're opinion is the reason that the majority of errors in C#, Java, JavaScript, Dart, D, and all the other languages that use exceptions have decided that all errors should crash the application and that you won't know about what can error. Programmers are LAZY. Making them do verbose things when they can't possibly handle it are going to cause them to reject the language feature.
- TeaBrain 2y ago"For example, if you indiscriminately catch Exception (instead of CreditCardExpiredException, SuspiciousActivityException, CardTypeNotSupportedException and so on) in order to recover from a credit card transaction failure, you may inadvertently catch SQLException as well, but that is a different type of error" All of the above examples of custom exceptions are great examples of things that should never be handled by exceptions. If the author was using a library that really threw exceptions like this, then it would probably be best to just find a new library which isn't arbitrarily throwing exceptions to create control flow logic.
- PaulHoule 2y agoThere is nothing wrong, I think, with having application-oriented exceptions, but you are going to either catch them individually or make them derive from some root like CreditCardException. Real life does not respect encapsulation, that is, it is not really your application's business to know that such a thing as a SQLException exists, other than how to log it, if SQL is hidden beneath a DAO layer. I mean, just because the beautiful architecture of your application doesn't have things like backhoes cutting through fibers in it, doesn't mean those things can't happen to you. There are a lot of things that will happen to your application that it can't understand and the best it can do is: (i) protect its own integrity (use finally) and (ii) abort, retry or ignore and (iii) hopefully have the wisdom to choose the right one of those.
- deleted 2y ago[deleted]
- breadwinner 2y ago> should never be handled by exceptions So you prefer to check for errors after every function call? That's what you had in C language, and the problem is that the logic gets buried inside all the error checking, and that makes code hard to read (and write).
- gnaritas99 2y ago[dead]
- PaulHoule 2y agoSome people will say the opposite. https://gen5.info/q/2008/07/31/stop-catching-exceptions/ https://gen5.info/q/2008/07/31/stop-catching-exceptions/ Checked exceptions don't cause people to write good error handling code, they just cause a crisis for no good reason when you are writing code that people will answer with some lame answer like try { action(); } catch(ActionException x) {} or try { action(); } catch(ActionException x) { throw new RuntimeException(x); } or try { action(); } catch(ActionException x) { throw new SomeExceptionThatWillCauseACrisisLater(x); } when you really should be doing something like try { action(); } finally { makeItRight(); } and finally deal with the exception at the end of the "work unit", see https://gen5.info/q/2008/08/27/what-do-you-do-when-youve-caught-an-exception/ https://gen5.info/q/2008/08/27/what-do-you-do-when-youve-cau... Look at the JDK 8 streams library of an example of a library that (a) is awkward as hell because you can't stream.map(this::someMethodThatMightThrowAndException) but (b) still handles errors improperly. Some versions of Lisp have a much better approach described here https://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts https://gigamonkeys.com/book/beyond-exception-handling-condi... in most languages what you can do is build a framework that controls execution in such a way that (in the context of a stream of work units) it can "separate the code that actually recovers from an error from the code that decides how to recover" as that article says as best you can.
- breadwinner 2y agoA bad programmer can write bad code no matter the language. Java lets you write good code if you're a good programmer. C# on the other hand makes you write bad code even if you're a good programmer. Why? Because you have no idea what exceptions are possible, and whether the handlers you have are even needed anymore.
- neonsunset 2y agoI participate in a couple of Java communities and checked exceptions are considered a huge anti-pattern in both. Please don't mistake preference for objective reality.
- symbol-mason 2y agoThe examples in that article (CreditCardExpiredException, SuspiciousActivityException, CardTypeNotSupportedException) show why no other languages follow Java's concept of checked exceptions. Those are examples of business logic or control flow being done by exceptions, which has been, in my experience, considered an anti-pattern for a very long time. Other languages use union types, enums, or other type system constructs to represent operations which may have multiple possible outcomes. You're correct that these languages don't support business logic exceptions, but that also isn't an acceptable practice outside of Java.
- breadwinner 2y ago> acceptable practice outside of Java. What is the acceptable practice outside of Java? Do you prefer to check for errors after every function call? That's what you had in C language, and the problem is that the logic gets buried inside all the error checking, and that makes code hard to read (and write).
- symbol-mason 2y agoThe general answer is "represent it in the type system". That's typically via discriminated unions like Rust's Result, or something which emulates it (such as OneOf or Dunet for C#, although it will be a native part of the language soon). Pattern matching, nullable types, and the Try* method conventions are also ways of representing the potential for failure explicitly.
- vips7L 2y agoChecked exceptions are represented in the type system. There is fundamentally no difference between these two: A b() throws C fn b() -> Result<A, C> A a = try { b() } catch (C c) { new A() } val a = b() match { Ok(a) => a Failure(c) => A() }