I'm sure most experienced programmers already know that using exceptions for flow of control in a program is highly inefficient. The time it takes to unwind the stack alone is ridiculous, let alone the fact that compilers don't tend to optimize for exception paths. The question is then what to replace it with? Do you set status and return an empty or a null? Do you always return a "result" object that includes both the result state and any return types?
My team is working on updating our shared components' architecture and are considering this question as we go. We've decided to move towards returning a result object and having "out" parameters for most of the new methods we're writing. While not ideal, this does mean we always use the same type of return value. We could also create subclasses of that return type with more propoerties instead of using out parameters.
At the same time, I'm working on creating some unit tests for our new code and building both the "happy path" tests and the tests that supply null, empty, and otherwise invalid values. I do like the idea of not throwing exceptions unless something truely exceptional has occured but we can swing too far in that direction, getting ourselves into unknown states or overly complicating the program logic to the point where it constantly checks system state instead of simply executing. Trade offs all around, I suppose.