Error handling can be done in different ways.

JavaScript and Python throw exceptions, while Rust is essentially throwing exceptions.
C and Go languages return an error value, and you must determine whether the value is -1 or null.
I've always wondered which way is better.
Not long ago, I read an article from many years ago.ArticleExplicitly proposeThrowing exceptions is better than returning status codesHis reasoning is very convincing, and it seems the article hasn't been translated into Chinese yet, so I translated it out.
Exceptions and Return Status Codes
Author: Ned Batchelder
Original website URL:nedbatchelder.com

In software, there are two ways to handle errors: throwing exceptions and returning status codes.
Almost everyone agrees that exceptions are a better way to handle errors, but some people still prefer returning status codes. This article explains why exceptions are a better choice.
I. Clean Code
Exceptions allow you to omit error-handling steps in most of your code. They automatically propagate upward through layers that do not catch exceptions. As a result, you can write code without any error-handling logic, which helps keep the code clean and readable.
Let's compare the two ways of writing the same simple function.
First, returning status codes.
STATUS DoSomething(int a, int b) { STATUS st; st = DoThing1(a); if (st != SGOOD) return st; st = DoThing2(b); if (st != SGOOD) return st; return SGOOD; }
In the example above, you must check DoThing1(a) andDoThing2(b) normal to proceed to the next step. If
throws an exception, there's no need for intermediate error checks.
void DoSomething(int a, int b) { DoThing1(a); DoThing2(b); }
This is just the simplest case. If you encounter complex scenarios, the noise from status codes will be more severe, while exceptions can keep the code clean.
II. Meaningful return values
Status codes consume valuable return values, forcing you to add code to determine if the return value is correct.
Some functions only need to return a normal value but now have to include error return cases. Over time, the codebase grows, functions become larger, and return values become more complex.
For example, many functions have overloaded return values: "return NULL if failed," or return -1 on failure. The result is that every time you call this method, you have to check if the return value is NULL or -1. If the function later adds new error return values, you must update all call points.
If an exception is thrown, the function only returns when it is successful, and all error handling can be simplified to one place.
III. More Rich Error Information
Status codes are usually integers, and the information they can convey is quite limited. Suppose an error is a file not found, then which file? The status code cannot convey that much information.
When returning a status code, it is best to log an error message in a dedicated error log, so the caller can obtain detailed information from it.
Exceptions are completely different; they are instances of classes, so they can carry a lot of information. Since exceptions can be subclassed, different exceptions can carry different data, forming a very rich error message system.
IV. Can Handle Implicit Code
Some functions cannot return a status code. For example, constructors do not have an explicit return value, so they cannot return a status code. There are also some functions (such as destructors) that cannot even be called directly, let alone return values.
Functions without return values, if not using exception handling, force you to come up with other methods to convey error messages or pretend these functions will never fail. Simple functions might achieve fault tolerance, but the codebase will grow continuously, and the likelihood of failure will also increase. Without a way to express failure, the system will only become more error-prone and harder to understand.
V. Visibility of Errors
Consider what happens if a programmer is negligent and fails to write error handling code.
If the return status code is not checked, the error will go undetected, and the code will continue to execute as if the operation succeeded. The code may fail later, but it might be after many steps of operation. How can you trace the issue back to where the initial error occurred?
On the other hand, if an exception is not caught immediately, it will propagate up the call stack, either reaching a higher catch block or reaching the top level and being handled by the operating system, which typically presents the error to the user. This is bad for the program, but at least the error is visible. You will see the exception, be able to determine where it was thrown, and where it should be caught, thus allowing you to fix the code.
This does not discuss the situation where errors are not reported. In this case, neither returning a status code nor throwing an exception is useful.
So, for errors that are reported but not handled, there are two possibilities: one is that the return status code hides the issue, and the other is that throwing an exception makes the error visible. Which one would you choose?
VI. Rebuttal
Famous programmer Joel Spolsky believes that returning status codes is better, because he thinks exceptions are a much worse form of goto statement.
"Exceptions are invisible in the source code. When reading code blocks, it's impossible to know which exceptions might be thrown and from where. This means that even with careful code review, potential errors cannot be discovered."
"An exception is a function creating too many possible exits. To write correct code, you must consider every possible code path. Each time you call a function that might throw an exception without immediately catching it, the function may suddenly terminate, or other unexpected code paths may occur."
These words sound quite reasonable, but if you change it to return status codes, you must explicitly check every possible return point of the function. So,You have traded explicit complexity for implicit complexity.This also has drawbacks; explicit complexity can make you see the trees but not the forest, and the code will become chaotic as a result.
When facing this explicit complexity, programmers get frustrated and either hide error handling with custom methods or simply omit it.
The former hides error handling, only changing explicit handling back to implicit handling, and is less convenient and feature-complete than the original Try method. The latter omits error handling even worse, as programmers assume some error will not occur, thus埋下风险.
VII. Conclusion
Returning status codes are difficult to use and cannot be used in some places. It hijacks the return value. Programmers may easily fail to write error handling code, causing silent failures in the system.
Exceptions are better than status codes. As long as your programming language provides exception handling tools, use them.
(End)


























