I can't say I'm a fan of these sorts of articles. "Which strategy is most performant?!" is rarely the appropriate measure for an error handling strategy, it's more nuanced than that. Concerns like what makes a recoverable error vs an unrecoverable one are more important. Ensuring correctness is more important. The usability of an API is more important. Readability and maintainability are more important. Knowing what errors mean in terms of your domain model is more important.
Use what fits for your situation, don't take the "when all I have's a hammer..." attitude to anything. Sometimes return codes make sense (eg in hot-loop code). Sometimes exceptions make sense (in constructors, for example. And no, two-step initialisation is not a good alternative.). Sometimes neither make sense and you actually should just terminate the whole program (out-of-memory). Sometimes contracts make more sense (precondition checks, validating function arguments).
Anyway, regardless of your strategy if you can provide some method of querying if a thing can succeed to your API, do so; it's always better to handle errors by just making sure you don't cause them!
Use what fits for your situation, don't take the "when all I have's a hammer..." attitude to anything. Sometimes return codes make sense (eg in hot-loop code). Sometimes exceptions make sense (in constructors, for example. And no, two-step initialisation is not a good alternative.). Sometimes neither make sense and you actually should just terminate the whole program (out-of-memory). Sometimes contracts make more sense (precondition checks, validating function arguments).
Anyway, regardless of your strategy if you can provide some method of querying if a thing can succeed to your API, do so; it's always better to handle errors by just making sure you don't cause them!