In particular I often have code that looks like this:
if (obviously_no_result(request))
return null;
calculation = check_something(request);
if (calculation_shows_no_result(calculation))
return null;
if (more_expensive_check_shows_no_result(calculation))
return null;
full_calculation = expensive_full_check(request, calculation);
if (!full_calculation)
return null;
result = get_result_structure(request, full_calculation);
notify_hooks(result);
return result;
i.e. the fact that additional calculations are needed between ifs means that else-if cannot be used, and the performance hit of putting all calculations up front is unacceptable when most calls will (intentionally) fail.
I've used this style for 20 years for efficiency and clarity. It is much more clear than 'only return once' style code. When I wrote a textbook with an example using this style it garnered a bad Amazon review from someone who complained it showed I was a terrible programmer, because I didn't follow 'best practice' as taught in their Java course. Not that I'm bitter, or anything…
The complaint is that, if I need to do something for every failure (like adding a log, say), it is easy to forget a place to add it. I'm increasingly thinking that goto is actually a pretty good solution, and labels are a form of documentation. Though my need to be seen as non heretical probably stops me from using it in anger:
if (obviously_no_result(request))
goto no_result;
calculation = check_something(request);
if (calculation_shows_no_result(calculation))
goto no_result;
if (more_expensive_check_shows_no_result(calculation))
goto no_result;
full_calculation = expensive_full_check(request, calculation);
if (!full_calculation)
goto no_result;
valid_result:
result = get_result_structure(request, full_calculation);
notify_hooks(result);
return result;
no_result:
notify_error_hooks(request);
return null;