3 ms·
Here's an example C# pseudocode to illustrate the problem with not having checked exceptions: Programmer A writes this C# code: class A { public static
by petilon 8y ago
Here's an example C# pseudocode to illustrate the problem with not having checked exceptions:
Programmer A writes this C# code:
class A {
public static void startFoo() {
if (/* Foo is not installed */)
throw new FooNotInstalled();
// ...
}
}
Programmer B calls the above code like this:
class B {
try {
A.startFoo();
}
catch (FooNotInstalled) {
// Tell user to purchase Foo
}
}
Later programmer A updates his code because there are newer versions of Foo and he needs the newest version:
class A {
public static void startFoo() {
if (/* Foo is not installed */)
throw new FooNotInstalled();
if (/* Foo version is too old */)
throw new FooVersionTooOld();
// ...
}
}
Now the code written by Programmer B crashes even though it compiles fine. That's bad.
Had this been Java, programmer would be would be alerted to the fact that he needs to decide what do do if the version of Foo is too old. This is good.
So listing exceptions that can be thrown is a good thing because it helps you write more reliable code. If you are lazy you can always defeat the system by declaring your method as throwing a parent (or the root) exception class, in which case it is no worse than C#.
- bunderbunder 8y agoAgreed that there are some benefits to having exceptions as part of the interface, but there are ergonomic challenges around being annoyed with a bunch of breaking changes in spots where you really don't want to be hassled with the details. I see it causing more problems than it solves. When people are forced to handle exceptions, they often handle them badly. IMO, an immediate program crash with a nice clear stack trace due to an unhandled exception is almost always preferable to a festering, difficult-to-trace (or even detect) bug due to an error condition that got swept under the carpet. You're very likely to get some of the latter sneaking in with an interface change like the above. The person who made the change is going to be the one who gets stuck getting the code to compile. If they are faced with tens (maybe even hundreds) of compile errors, they're going to be forced to make a whole bunch of unplanned changes to a bunch of code they didn't write and might poorly understand even before they can get to the point of being able to start running the unit tests.
- EdwardDiego 8y ago> So listing exceptions that can be thrown is a good thing because it helps you write more reliable code. This is entirely valid Java: public class FooBob { class ExampleException extends RuntimeException { } public boolean foo(Boolean bob) throws ExampleException { ... } } You don't need to throw a checked exception to document that your public API throws an exception. You're right, that throwing a new checked exception would force programmer B to handle it, but frankly, I'd rather that programmer B a) versioned his dependencies or b) read the source code of his dependencies. Also, not sure about C# land, but in Java land, if you're writing libraries, we have tools to enforce semantic versioning based on public API changes (the Maven enforcer plugin with the semver plugin) which would also communicate breaking API changes. I would much prefer that enforcing the communication of backwards-incompatible API changes not be done by the compiler.
- pacala 8y agoExceptions are for error reporting. Pass them through all the way to the top, and log them. Enforce module preconditions proactively. if(!isInstalled(Foo)) { purchase(Foo) } else { start(Foo) }
- smsm42 8y agoThis! Java is hugely overusing exceptions for reporting situations that are completely normal (probably because it didn't have anything like Option type or any way to return error results). Exception should be for "somebody stole our HD and we can't read data" or "database have died and we can't continue, all panic!", not for "user made a typo and we need to display an error message". Using exceptions for routine flow control is bad design.
- smsm42 8y agoThe problem is what would happen in reality is that programmer B would do catch(Exception e) { log(e); continue; } somewhere, because otherwise it doesn't work or requires to change signatures to 20 methods, and all good intentions will die with it. Yes, I've seen libraries (and not just something a random kid put on github, ones which are very mainstream and recommended for their use case) with APIs just plain declaring "throws Exception" because who cares, right? We warned you we might throw exceptions, deal with it! But why go to libraries - in Java's own stdlib AutoCloseable.close() is declared "throws Exception"! Tell me again about nice exception hierarchy and versioning and stuff. And of course writing "throws Exception" on every single test is hugely annoying. Yes, I do not want to handle exceptions in the tests, that's the whole point of the test!