7 ms·
I've always kinda hated exceptions as it makes the contract between a caller and a callee hard to determine, and makes your code highly coupled. I prefer the Go
by zeroCalories 2y ago
I've always kinda hated exceptions as it makes the contract between a caller and a callee hard to determine, and makes your code highly coupled. I prefer the Go or Rust style of handling it through return values. Briefly skimming the language, I'm not sure if there is anything that fixes that?
I think this kind of model could be cool if your IDE could dynamically determine all uncaught exceptions for a function, and lets you jump to each possible place where the exception could be thrown. Not sure how you handle coupling though. This seems like it would result in an insanely volatile control flow graph.
- mbmjertan 2y agoThis is what IntelliJ does for Java. A problem is reported whenever you have a function that throws exceptions and isn’t caught in a caller anywhere in the project, and you can jump to implementation or calls easily. However, exceptions that a function can throw are part of the function signature in Java unless they extend RuntimeException (and in that case your program won’t compile if you throw an exception without adding it to the signature). While the circumstances in Java make it much easier for IDEs to report uncaught exceptions, it’s a solvable problem for non-runtime exceptions using static analysis. On the other hand, returning standardised Ok/Err-wrapped values seems like a simpler approach, both in terms of tooling support and developer convenience.
- DarkNova6 2y agoI think once Java has finished up exception switch-case it will be a model followed by other languages. Being able to catch exceptions at both, method and transaction boundaries will be a boon for readable control-flow.
- throw156754228 2y agoAlgebraic effects is going in completely the opposite direction.
- mrkeen 2y ago> and transaction boundaries What are transaction boundaries? Is Java getting transactions?
- otabdeveloper4 2y ago> ...as it makes the contract between a caller and a callee hard to determine, and makes your code highly coupled. I prefer the Go or Rust style of handling it through return values. There is literally (literally!) no difference at all between throwing and exception and returning it as a variable. Except for the fact that in the exception passing style you have to write the boilerplate by hand, instead of letting the compiler do it for you. Why anybody with a sane and functioning brain would want to do that by hand in 2024 I will never understand.
- ratscylla 2y agoI think people like it because the control flow of a given program is more obvious when you write it that way. No one can "throw Foo" three libraries down from their caller as an "API". See https://go.dev/blog/errors-are-values https://go.dev/blog/errors-are-values
- wvenable 2y agoYou're just trading one type of control flow visibility for another. With even the most basic amount of error-return handling the actual control flow of your program is quite obscured.
- psd1 2y agoAs an implementation detail, exceptions are usually much more expensive than just popping the stack, as computation is needed for each frame you traverse. Having both throw and return is like regex: now you have two problems.
- tylerhou 2y agoExceptions are less expensive in the unexceptional case. Consuming a Result value requires a branch to see whether it holds Error. That is not necessary if the function returns a value directly (and throws an exception on error).
- 2y ago
- NBJack 2y agoIf go didn't naturally eat error context, I'd like it more. But in the time I've used it, it makes errors much, much more painful to root cause without a debugger.