4 ms·
> One of the biggest flaws in C#, in my experience, is lack of checked exceptions. I couldn't disagree more. Checked exceptions in Java have ruined a generati
by wvenable 3y ago
> One of the biggest flaws in C#, in my experience, is lack of checked exceptions.
I couldn't disagree more. Checked exceptions in Java have ruined a generation of programmers.
The truth is, under checked exceptions, to satisfy the compiler the function that you called would declare that it throws a SomeModuleException and the programmer who wrote that function would put all his code in try/catch block that catches all errors and rethrows a SomeModuleException with the real exception passed as the cause.
Checked exceptions just don't work.
- jitix 3y agoYou’re both right and wrong. Checked exceptions slow down development, make code ugly and in my theoretical opinion are an anti-pattern that should never be used. However in small to mid sized enterprise software companies with average developer talent it’s important to keep boundaries (and blame) clear. In the scenario in question, the CTO will blame OP and make them work the weekend to diagnose/fix it, so wrapping the other exception and throwing their own SomeModuleException will cover their ass. Java is popular for all the wrong reasons. Believe it or not there are hundreds of such companies in the US alone heavily using Java in this manner and then there is the whole offshore development segment.
- adamwk 3y agoBut even with unchecked exceptions, the exception value or description will still show up in the logs. I don’t understand how checked exceptions save you from a tyrannical CTO
- jitix 3y agoGood point, but in my experience siloed teams (often if different continents) usually don’t standardize on error messages and codes, and a vague message like “Invalid name” doesn’t indicate which layer the message is coming from. From operations’ point of view the bug will be pinned on the owner of the service that is returning the JSON to the client/app and it’s up to them to trace it down the layers. A hierarchy of wrapped exceptions helps with that. Kind of like saying “I can’t do it because XYZ didn’t do what they were supposed to do”. So low key corporate blame game in code. I know that the usual HN crowd doesn’t work at/know about companies that follow this, but this pattern is way more prevalent in the broader “IT” industry esp among offshore centres.
- rogerkeays 3y agoI put Java's popularity down to good support for Corporate-Oriented Programming ;)
- slt2021 3y agoCoproporate-Oriented would be a better description
- breadwinner 3y agoThat's how you do it in C#... See InnerException [1]. What a good programmer would do is to throw a new exception, and fix the callers to handle the new error. https://learn.microsoft.com/en-us/dotnet/api/system.exception.innerexception?view=net-7.0 https://learn.microsoft.com/en-us/dotnet/api/system.exceptio...
- wvenable 3y agoThat assumes you have control over the callers. If you're writing a library, you don't. Checked assumptions are incompatible with polymorphism and even just basic abstraction afforded by functions. One can't arbitrarily change an implementation without changing the signature and breaking all the callers. The vast majority of cases, direct callers can't properly the handle the new error anyway. Callers either have to eat that exception, convert it (thus defeating the purpose of checked exceptions), or change their signature. Good programmers will change the signature and now every one of the callers of those methods have do the same thing. Ad infinitum.
- breadwinner 3y agoYou can have multiple implementations of database drivers, but they all throw a subclass of SQLException. So yes, polymorphism is certainly possible. And when you get a SQLException (for example SQLIntegrityConstraintViolationException), you don't want to just crash, or display whatever error message the database gave you... you want to, at the very least, provide guidance to the user on what corrective action to take. And in some cases the program can automatically take corrective action. And that's the reason for writing down a list of possible exceptions where recovery and retry are possible (aka checked exceptions).
- wvenable 3y agoThat's an extremely contrived example. What if now you want to do a NoSQL solution? Or a flat file? But really the problem is actually far worse than that. Checked exceptions are brittle under any kind of implementation change. If you have a function that calculates a rate just using arithmetic. But tomorrow it loads a flat file. And next week it uses SQL. And in a month it calls a web service. As a consumer, this is none of your concern -- that's the whole point of abstraction. It's even worse when dynamic (polymorhphism) or functional (external code calls you). What's the recovery from a SQLException anyway? How does that give you enough detail to do anything? You say SQLIntegrityConstraintViolationException but that's not the same type. Why does it matter that you declared it a SQLException over just Exception in that case?
- com2kid 3y agoFrom a type theory perspective, an exception is another type of return value that a function can have, and not documenting those in the function signature is absurd. I have seen libraries that make network calls that do the following: * Throw an exception on certain types of network errors * Return an HTTP error code for other types of network errors * Return an object with error set to true and an error string for other types of network errors NONE of those was documented, it is crazy. This actually bite me in prod when an undocumented exception that we hadn't seen in over a year of uptime was finally thrown. I had to look at network logs to try and figure out why it was being thrown (no checked exceptions in JS!), which itself is absurd.
- mrkeen 3y ago> and not documenting those in the function signature is absurd Exceptions can be thrown from anywhere. That's the documentation.
- jakewins 3y agoI think the issue is with checked exceptions as a solution to how to declare this signature, or at least with how they are designed in Java: if you add a new exception to the signature, every downstream call site needs to change, recursively. This means it is impossible to add new exceptions to library methods without breakage, and even in your own code it may mean hundreds of changes throughout your code to add a new exception type. Rusts solution seems to have improved this conundrum, where you can describe how to map the new error into an existing hierarchy in a single or a few places instead of at every call site
- kaba0 3y ago> This means it is impossible to add new exceptions to library methods without breakage That’s a feature, not a bug. If it wouldn’t, an exception of that kind could bubble up at a place you didn’t expect. Also, it doesn’t require that many changes, it only has to be changed up to the point where you intend handling it. I don’t see how rust would be immune to that. Though it is true that polymorphism with respect to checked exceptions would be great. The new generation of languages might have that (e.g. Koka)