Tip of the Week #76: Use absl::Status

Originally posted as TotW #76 on May 4, 2014

By Titus Winters

Updated 2020-02-06

Quicklink: abseil.io/tips/76

Some folks have questions about when and how to use absl::Status, so here are a few reasons why you ought to use Status, and some things to keep in mind when using it.

Communicate Intent and Force the Caller to Handle Errors

Use Status to force the caller to handle the possibility of errors. Since June 2013, a function returning an Status object cannot simply be ignored. That is, this code produces a compilation error:

absl::Status Foo();

void CallFoo1() {
  Foo();
}

Whereas these calls are fine:

void CallFoo2() {
  Foo().IgnoreError();
}

void CallFoo3() {
  if (!status.ok()) std::abort();
}

void CallFoo4() {
  absl::Status status = Foo();
  if (!status.ok()) LOG(ERROR) << status;
}

Why is it OK for Status to have an IgnoreError() method, while we just went through all this effort to make the compiler check that Status isn’t ignored? Imagine you’re the code reviewer looking at either CallFoo1() or CallFoo2(). The latter code snippets make the reviewer think “This function could have had an error, but the author thinks its OK to ignore it. Is it?” CallFoo1() does not trigger such a response.

Allow the Caller to Handle Errors Where They Have More Context

Use Status when it’s not clear in your code how to handle the error. Instead, return a Status, and let the caller, who may have more appropriate insight, handle the error.

For example, logging locally might impact performance, such as when writing infrastructure code. If your code is called in a tight loop, even a call to LOG(INFO) may be too expensive. In other cases, users may not really care if a call succeeds, and find the log spam intrusive.

Logging is appropriate in many cases, but functions that return Status don’t need to LOG to explain why something failed: they can return the failure code and error string and let the caller decide what the right error handling response should be.

Isn’t This Just Re-Inventing Exceptions?

The Google style guide famously prohibits exceptions (it’s discussed more than any other prohibition). It can be tempting to view absl::Status as a poor- man’s exception mechanism, with a lot more overhead. While there may be similarities on the surface, absl::Status differs in its need to be explicitly handled, rather than just passed up the stack invisibly as an unhandled exception. It forces engineers to decide how to handle errors, and explicitly documents that in compilable code. And finally, returning an error using a absl::Status is orders of magnitude faster than throwing and catching an exception. These features may seem onerous when writing code, but the result is a net win for everyone that has to read that code, and for Google as a whole.

Conclusion

Error handling is one of the easiest things to get wrong: these are inherently the edge cases. A utility like Status that adds consistency to error handling across API boundaries, projects, processes, and languages helps us minimize a large class of “There were issues with our error handling” bugs. If you’re designing an interface that needs to express the possibility of failure, please use Status if you don’t have a pretty strong reason to do otherwise.


Subscribe to the Abseil Blog