Most program languages have some kind of exception handling; some languages have return codes, others have try/catch, or rescue/retry, etc., each with its own pecularities in readability, robustness, and practical effectiveness in a large group development effort. Which one is the best and why ?
try/catch/finally does the job admirably.
It allows the programmer to handle specific conditions as well as general failures gracefully.
All said and done I'm sure that each is as good as any other.
I'd have to go with the try / catch concept. I feel like in terms of readability this provides the most to a code maintainer. It should be fairly straight forward to find the chain of function calls as long as the exception is properly typed and the associated message contains detailed enough data (I personally do not like including stack traces but I know plenty who do and this would make this even more traceable.) The return code implementation requires an external table of code definitions on a program by program basis. Which from personal experience is both unwieldy to maintain and reference.
I would say that depends on the nature of your problem. Different problem domains could require almost arbitrary error messages, while other trivial tasks just can return NULL or -1 on error.
The problem with error return codes is that you're polluting/masking the error since it can be ignored (sometimes without the API client not knowing they should check for the error code). It gives a (reasonably) valid output from the method at hand.
Imagine you have an API where you ask for a index key for some map, store it in a list, and then continue running. The API then at a later moment sends a callback, and that method might then traverse the table, using the key which might be -1 in this example (the error code). BOOM, the application crashes as you index to -1 in some array, and those kinds of problems can be very hard to nail down. This is still a trivial example, but it illustrates a problem with error codes.
On the other hand, error codes are faster than throwing exceptions, and you might want to use them for frequently accessed method calls - if it is appropriate to return such an error code. I would say that trying to encapsulate these kinds of error codes within a private assembly would be quite OK since you're not exposing those error codes to the client of the API. Always remember to document these methods rigorously since these kinds of application nukes can linger around in an application for a long time since they were triggered before it goes off.
Personally, I prefer a mix of them both to some extent. I use exceptions just for that - exceptions - when the program runs into a state which was not expected and needs to inform something has gone way out of plan. I am not a sucker of writing try/catch blocks all over my code, but it's all down to personal preference.
Best for what? Language design is always about tradeoffs. The advantage of return codes is that they don't require any runtime support beyond regular function calls; the disadvantages are 1) you always have to check them 2) the return type has to have a failure value that isn't a valid result of the function call.
The advantage of automatic exception handling is that error conditions in your code don't disappear.
The differences between exception handling semantics in various languages (and Lisp's condition system, E's ejectors, etc) mainly show up in how stack unwinding is dealt with when program execution should continue.
To summarize, though: automatic exception handling is extremely valuable when you need to write readable, robust software, especially in a large team. Letting the computer track error conditions for you gives you one less thing to think about when reading code, and it removes an opportunity for error. The only time I'd use return codes to indicate errors is if I was implementing a language with exception handling in one that didn't have it.
For unusual perspective on exception handling, see Haskell's Control.Exception
monad