Obviously, error handling in general is a big topic, and that best practice is highly dependent on the capabilities of the language you work with and how the program you code is suitable for other routines. Therefore, I will limit my answer to VBA (used in Excel) and subroutines such as libraries of the type that you describe.
Exceptions to Error Codes in Library Programs
In this case, I would not use a return code. VBA supports an exception handling form, which, although not as powerful as the more standard form found in C ++ / Java / ??. NET is pretty similar. Therefore, the recommendations of these languages are generally applied. You use exceptions to indicate calling procedures that the called routine cannot do this work for any reason. You handle exceptions at the lowest level, where you can do something meaningful in this failure.
Bjarne Stroustrup provides a very good explanation of why exceptions are better than error codes for this kind of situation in this book. (The book is about C ++, but the principles for handling C ++ exceptions and handling VBA errors are the same.)
http://www2.research.att.com/~bs/3rd.html
Here is a good passage from Section 8.3:
When a program consists of separate modules, and especially when these modules are developed separately by the library, error handling should be divided into two separate parts: [1] Reporting errors that cannot be resolved locally [2] processing errors found elsewhere libraries can detect runtime errors, but there is no idea what to do with them. The library user can know how to deal with such errors, but cannot detect them - otherwise they will be processed in the user code, and not to the left, to find the library.
Sections 14.1 and 14.9 also discuss exceptions and error codes in the context of the library. (There is a copy of the book on the Internet at archive.org.)
There is probably a lot more about this in stackoverflow. I just found this, for example:
Exception vs. Error Code vs. assert
(There may be errors associated with proper resource management that need to be cleared when using exceptions, but they really don't apply here.)
Exceptions in VBA
This is how an exception is thrown in VBA (although VBA terminology "causes an error"):
Function AddArrays(arr1, arr2) Dim i As Long Dim result As Variant ' Some error finding code here, eg ' - Are input arrays of same size? ' - Are input arrays numeric? (can't add strings, objects...) ' - Etc. 'Assume errorsFound is a variable you populated above... If errorsFound Then Call Err.Raise(SOME_BAD_INPUT_CONSTANT) 'See help about the VBA Err object. (SOME_BAD_INPUT_CONSTANT is something you would have defined.) End If ' If no errors found, do the actual work... ReDim result(LBound(arr1) To UBound(arr1)) For i = LBound(arr1) To UBound(arr1) result(i) = arr1(i) + arr2(i) Next i AddArrays = result End Function
If this procedure does not catch the error, VBA will provide other routines above it in the call stack chance (see the following: VBA "Bubble Up" error ). Here's how the caller can do this:
Public Function addExcelArrays(a1, a2) On Error Goto EH addExcelArrays = AddArrays(a1, a2) Exit Function EH: 'ERR_VBA_TYPE_MISMATCH isn't defined by VBA, but it value is 13... If Err.Number = SOME_BAD_INPUT_CONSTANT Or Err.Number = ERR_VBA_TYPE_MISMATCH Then 'We expected this might happen every so often... addExcelArrays = CVErr(xlErrValue) Else 'We don't know what happened... Call debugAlertUnexpectedError() 'This is something you would have defined End If End Function
What it means to do something meaningful depends on the context of your application. In the case of an example of the above, he decides that some errors should be handled by returning the error value that Excel can put in the cell of the worksheet, while others require an unpleasant warning. (Here, where the VBA case in Excel is not actually a bad concrete example, since many applications distinguish between internal and external procedures and between the exceptions that you expect to be able to handle and the error conditions that you just want to know about but for which you have no answer.)
Do not forget the statement
Since you mentioned debugging, the role of statements is also worth noting. If you expect AddArrays to be called only by routines that have actually created their own arrays or otherwise verified, they use arrays, you can do this:
Function AddArrays(arr1, arr2) Dim i As Long Dim result As Variant Debug.Assert IsArray(arr1) Debug.Assert IsArray(arr2) 'rest of code... End Function
A fantastic discussion about the difference between statements and exceptions here:
Debug.Assert vs Exception Throwing
I gave an example here:
Is affirmation evil?
Some VBA Recommendations on Shared Array Processing Procedures
Finally, as a VBA note, there are VBA variants and arrays with lots of errors that should be avoided when trying to write generic library routines. Arrays can have more than one dimension, their elements can be objects or other arrays, their start and end indices can be any, etc. Here is an example (untested and not trying to be exhaustive) that takes into account some of them:
'NOTE: This has not been tested and isn't necessarily exhaustive! It just 'an example! Function addArrays(arr1, arr2) 'Note use of some other library functions you might have... '* isVect(v) returns True only if v is an array of one and only one ' dimension '* lengthOfArr(v) returns the size of an array in the first dimension '* check(condition, errNum) raises an error with Err.Number = errNum if ' condition is False 'Assert stuff that you assume your caller (which is part of your 'application) has already done - ie you assume the caller created 'the inputs, or has already dealt with grossly-malformed inputs Debug.Assert isVect(arr1) Debug.Assert isVect(arr2) Debug.Assert lengthOfArr(arr1) = lengthOfArr(arr2) Debug.Assert lengthOfArr(arr1) > 0 'Account for VBA array index flexibility hell... ReDim result(1 To lengthOfArr(arr1)) As Double Dim indResult As Long Dim ind1 As Long ind1 = LBound(arr1) Dim ind2 As Long ind2 = LBound(arr2) Dim v1 Dim v2 For indResult = 1 To lengthOfArr(arr1) 'Note implicit coercion of ranges to values. Note that VBA will raise 'an error if an object with no default property is assigned to a 'variant. v1 = arr1(ind1) v2 = arr2(ind2) 'Raise errors if we have any non-numbers. (Don't count a string 'with numeric text as a number). Call check(IsNumeric(v1) And VarType(v1) <> vbString, xlErrValue) Call check(IsNumeric(v2) And VarType(v2) <> vbString, xlErrValue) 'Now we don't expect this to raise errors. result(indResult) = v1 + v2 ind1 = ind1 + 1 ind2 = ind2 + 1 Next indResult addArrays = result End Function