How to clean up error handling in a function? - vb6

I am looking at code written by someone else.
Some of the big functions are a mess, with changes to the error handling at many points throughout the function. There is a variety of On Error Goto ErrHandler, On Error Goto 0, On Error Resume Next, as you go through the function.
What would be the best way to go through and clean up this error handling so that there is just one On Error Goto ErrHandler at the top of the function as it should be?

I don't think that having a single Error Handler is necessarily the best solution.
If you have a huge function with one error handler and something goes wrong, you have no idea at which point it failed.
It sounds to be as though the functions you describe have the correct error handling in them but that doesn't mean it is easy to read.
Maybe the best solution is to re-factor the big functions into several smaller ones which can have their own single error handler that way when an error occurs you only have a few lines to track down the bug?
You could use the existing error handler statement to give you suitable markers for code re-factoring.

It's hard to say without looking at the code in question, but there are times when several different types of error handling in a single function is legitimate. In general, a single On Error GoTo ErrHandler at the top of the function serves the same function as an enclosing try/catch block in a language that supports exceptions -- it's there to catch the unexpected errors that occur.
However, within the function, there may be places where an error is a normal, expected occurrence that you want to check for inline. For example, say you're going access a network drive, where you have to account for the remote server being offline, the network down, etc. In this case, even though there's an On Error GoTo ErrHandler statement at the top, you can turn that off locally with an On Error Resume Next and try to access the drive. If an error occurs, VB6 will now just fall through to the next statement where you can check Err.Number for anything other than 0. This is analogous to a nested try/catch to trap an expected error condition that you can handle locally. Once execution has passed beyond the risky code, you have to mark the end of the section where you're going to "manually" check for errors this way with another On Error GoTo ErrHandler statement to re-enable the function-level handler.
So there's a case where more than one On Error... statment is valid. The argument can be made that the risky function should be refactored out and have its own handler, but you'd still have to deal with the specific (expected) error return values from that separate function, because the called function probably won't know what to do in the face of these errors in the context of the calling function. You would still handle that with the short-term On Error Resume Next technique.
On Error GoTo 0 disables all error handling, letting VB6 bail out of your function whenever an unexpected error occurs. I'm having a hard time coming up with a non-contrived situation where that would be a good option.

Related

What does call stack results in error reports mean?

I am trying to understand the Go 1.13 error handling from https://pkg.go.dev/github.com/pkg/errors?tab=doc#pkg-overview but could not get the meaning of the following description:
which when applied recursively up the call stack results in error reports without context or debugging information
Could someone please provide an example in corresponding to sentence above.
What is the advantage of error in Go 1.13 in comparing to old style error handling?
Reading the next section on the page could potentially enlighten you.
The "err" being returned recursively, is the error being propagated to the caller, ultimately reaching the top level caller (main for instance), this is what this means.
Now if the cause or detail of the error is not specified, it is going to be very hard to know how to fix it. Providing context, ensures that the emitter of the error can be easily identified.

Replacing golang error codes with panic for all error handling

We have medium sized application written in go. From all the code lines about 60 percent goes to code error handling. Something like this:
if err != nil {
return err
}
After some time, writing this lines over and over again becomes tiresome and we are now thinking to replace all error codes with panics.
I know panics aren't meant to be used like that.
What can be potential pitfall and does anyone have experience with something similar ?
The main pitfall would be a widespread use of hammers to drive screws. Panic is for unrecoverable/unexpected errors, error return values are for recoverable/expected errors.
Replace the word "panic" with "crash", because that is conceptually what a panic is. Do you honestly want to write an application that by design crashes whenever anything goes in any way remotely wrong? That would be the most fragile application on Earth, the very antithesis of fault tolerance.
As all the comments suggest you could be signing up for a disaster and let me add, whosoever is going to maintain this code will go insane trying to figure out what exactly went wrong when things do go awry if you don't do proper error handling (even if that person is you, it's going to haunt you).
Just repeating what others have said - the problem is being unable to differentiate between these two
a predictable & possibly recoverable condition
perhaps what is unrecoverable (need to exit the application or be handled at a higher level - this may be coming from your own application's conditions or some third party library, but is forcing you out of your normal execution path)
Panics are reserved for the latter types.

Is function parameter validation using errors a good pattern in Go?

Is parameter validation using error return codes considered good practice ? I mean where should somebody use errors vs panics (are there any guidelines?).
For instance:
Is checking for non-nil + returning an error if it is nil a good
practice ?
Or checking for correct integer ranges etc.
I imagine that using errors that often would make Go feel very C-ish and would look pretty bad. Are panics a good alternative in those situations ?
Or should a Gopher use the Python/Ruby/JS-approach "just let it fail" ?
I'm a bit confused because panics are for real "errors" in my understanding. But using errors all the time is just bad.
And even if I would return error code: What could I do if somebody passes wrong parameter to my function but ignores the errors codes ? -> Nothing! So honestly I would say panics are nice for those situations but in a language where error codes are used over panics this is not very clear.
"Escaping" panics1 in Go (I mean, those which might be produced by the functions comprising the public API of your package) are to deal with errors programmers do. So, if your function gets a pointer to an object, and that can't be nil (say, to indicate that the value is missing) just go on and dereference the pointer to make the runtime panic itself if it happens to be nil. If a function expects an integer that must be in a certain range, panic if it's not in that range — because in a correct program all values which might be passed to your function are in that range, and if they don't then either the programmer failed to obey the API or they did not sanitize the value acquired from the outside which, again, is not your fault.
On the other hand, problems like failure to open a file or pefrorm some other action your function is supposed to perform when called correctly should not cause panics and the function should return an appropriate error instead.
Note that the recommendation for explicit checking for null parameters in the functions of public APIs in .NET and Java code has different goal of making such kinds of errors sort-of more readable. But since 99% of .NET and Java code just lets all the exceptions propagate to the top level (and then be displayed or may be logged) it's just replacing one (generated by runtime) exception with another. It might make errors more obvious—the execution fails in the API function, not somewhere deeper down the call stack—but adds unnecessary cruft to these API functions. So yes, this is opinionated but my subjective opinion is: to let it just crash is OK in Go—you'll get a descriptive stack trace.
TL;DR
With regard to processing of run-time problems,
panics are for programming errors;
returning errors is for problems with carrying out the intended tasks of functions.
1 Another legitimate use for panics is quick "cold-path" returning from deep recursive processing/computation; in this case panic should be caught and processed by your package, and the corresponding public API functions should return errors. See this and this for more info.
The answer to this is subjective. Here are my thoughts:
Regarding panic, I like this quote from Go By Example (ref)
A panic typically means something went unexpectedly wrong. Mostly we use it to fail fast on errors that shouldn’t occur during normal operation, or that we aren’t prepared to handle gracefully.
In the description of your use case, I would argue that you should raise an errors and handle the errors. I would further argue that it is good practice to check the error status when one is provided by the function you are using and that the user should check if one is provided in the documentation.
Panics I would use to stop the execution if I run across an error that is returned from the function you are writing that I check and don't have a way to recover from.

Trap error or 'Resume Next'

I realise this is an older programming environment, but I have to clean up some VB6 code and I am finding that most of it uses:
On Error Resume Next
What is the general consensus about the use of On Error Resume Next?
Surely, if there is an error, you would want the app to stop what it was doing, rollback any data changes, and inform the user of the error, rather than just resuming.
When is it a good idea to use On Error Resume Next?
It is perfectly reasonable to use On Error Resume Next to implement local structured error handling. This involves testing for an exception and acting on it of course, as well as disarming the mechanism afterward. Example:
On Error Resume Next
GetAttr strFilePath
If Err Then
On Error GoTo 0
'Deal with "no file" scenario.
Else
On Error GoTo 0
'Open and process the file.
End If
That's just a simple example where only one sort of exception is expected. In some cases it is necessary to test Err.Number for specific values and take different actions based on them.
The unstructured approach based on GoTo label can often work as well, but it is hardly superior in most instances. In VBScript the pattern shown above is the only form of exception handling you even have since there are no GoTos or labels.
What's objectionable is arming explicit exception testing at the head of every procedure and ignoring it... a sort of Trust the Force, Luke approach to trying to mask coding errors.
I have found it useful in functions where an error would not warrant the user being interrupted with the issue. A good example is in the resize event. If you make a mistake or there's a problem in the resize event then you probably don't want the user to see this, as it probably wouldn't affect functionality.
I would say in general, use it sparingly.
Almost never - unless used consciously for example on a line where a successful call will set a particular return value, and the subsequent code handles the return value to cater for the error case.

PL SQL - Return SQLCODE as OUT parameter is accepted?

I have a procedure that returns an OUT parameter.
procedure foo (in_v IN INTEGER, out_v OUT integer)
BEGIN
...
EXCEPTION
WHEN OTHERS THEN
--sh*t happend
out_v := SQLCODE;
END
That parameter will be 0 if everything goes OK, and <> 0 if something ugly happened.
Now, if sh*t happens along the way, an exception will be thrown.
Is it ok to assing the SQLCODE value to the OUT parameter ? Or is this consideres a code smell, and I will be expelled from the programming community ?
Thanks in advance.
If there is no additional handling of the error, I would probably advise against it. This approach just makes it necessary for each caller to examine the value of the out parameter anyway. And if the caller forgets it, a serious problem may pass unnoticed at first and create a hard to debug problem elsewhere.
If you simply don't catch OTHERS here, you ensure that the caller has to explicitly catch it, which is a lot cleaner an easier to debug.
Whether it's OK or not depends on what you're trying to achieve with it, I suppose. What problem are you trying to solve, or what requirement are you trying to meet?
the usual behaviour with errors is to gracefully handle the ones that you expect might happen during normal functioning and to allow those that you do not expect to be raised, so this does look odd.
Its ok, but I don't recommend it. By doing it this way you're forcing the calling code to do non-standard error handling. This is fine if you are the only person ever calling the code and you remember to check the error code. However, if you're coding in a large system with multiple programmers I think you should be kind to your fellow programmers and follow the standard way of exception handling supported by the language.
If you do decide to go down that route, also pass back SQLERRM as without the error text you only have the error code to go by. After years of catching "-20001" for the hundreds of application errors in 3rd party software the SQLERRM is often important.
This coding style is not a good idea for a number of reasons.
First, it is bad practice to mix errors and exceptions, even worse practice to mix return values and exceptions. Exceptions are meant to track exceptional situations - things completely unexpected by normal programming such as out of memory issues, conversion problems and so on that you normally would not want to write handlers at every call site for but need to deal with at some level.
The second worrying aspect of the coding style is that your code is effectively saying when an exception is encountered, the code will signal to its caller that something bad has happened but will happily throw away ALL exception information except for the SQLCODE.

Resources