Fog Creek Software
Discussion Board




Evil and truly evil

I am not personally of the school of thought that thinks all GOTOs, in all cases, are intrinsically truly evil. In some (relatively unusual) cases I think they may be the least bad alternative. This doesn't mean I would pepper my code with GOTO, but if once in a blue moon, I ran across one for a reasonable purpose, I wouldn't worry about it.

That said, even so, I do think there is an evil aspect to GOTOs.  Namely what happens to them later.  When a person revises or debugs code, they will often remove GOTOs, replacing them with some other construct, and this itself introduces the risk of creating new bugs.

What I am trying to say is the attitude of programmers about GOTO, arguably makes them more evil, than they are to start with.

S. Tanna
Wednesday, May 21, 2003

Sorry, press submit too early

Anyway do you agree?

Does this apply to any other programming constructs?

S. Tanna
Wednesday, May 21, 2003

Hi,

totally agree :)  Ive recently run across a case exactly like that.
There was some legacy code we were supporting that used goto inside methods for cleanup code, roughly (from memory) like this:

if(condition is good)
do stuff
else
goto cleanup
end if

if(condition is still good)
do stuff
else
goto cleanup
end if

cleanup:
do cleanup stuff

The code was verra clean overall, most code Ive had to maintain written by someone else is a pita, but this code I was able to follow throughout with only verra small problems.
..Im not arguing that this was *because* of the goto, the original coder was very good in many, many ways, but certainly the goto in no way hurt the readability of the code.

So then we got a new programmer in :)  a java man by training I believe.
He went through this area of legacy code and stripped out the gotos, replacing them with some painfully odd construct that was not nearly as easy to read or maintain and called it good ;(

we've since had to fix 7 separate bugs caused by this, but no one (except myself) is willing to accept that the removal of the goto's was a bad/pointless thing to do, or that the code is now harder to maintain.

goto's are evil, I dont believe Ive ever used them myself, but in this case they were being used cleanly and well and causing absolutely no problems to anyone except incompetent swine who were unable to accept coding standards different from what they were used to.

FullNameRequired
Wednesday, May 21, 2003

Your thesis seems to be that seeing a goto provokes a maintenance programmer into an unnecesary refatoring.

I know of half a dozen situations where a goto is the best solution.

However, I have never found as situation where I needed to use one.

Every time I have encountered a goto in production enviroment it has been in twisted pile of crap hacked together by an incompetent.

So, yes when I see a goto I examine the code more rigorously.

Other control structures are much more robust. Gotos must be checked carefully with every coding change.

So, there is a direct cost saving in making an extra effort in code that will need regular maintenance.

Anonymous Coward
Wednesday, May 21, 2003

"He went through this area of legacy code and stripped out the gotos, replacing them with some painfully odd construct that was not nearly as easy to read or maintain and called it good."

Now _that_ is truely evil.

I've seen goto used constructively quite often in the Linux kernel - often as FullNameReq described.  Nothing wrong with that.  In fact, I find it much more readable that the use of something like a C++ autoptr used for maintaining a mutex lock/unlock within the context of a function call.  Some think its elegant, I find it ugly.  But there is no accounting for taste.

Another evil: forcing code "style" on developers.  You get this all the time from the XP fans.  Truly a sign of immaturity is not tolerating another's code style, and when modifying code, not leaving the style intact.

Nat Ersoz
Wednesday, May 21, 2003

It is impossible to write good Visual Basic code without them.

Geoff Bennett
Wednesday, May 21, 2003

Geoff, many would argue your sentence is true without the last two words... [grin]

Insofar as anticipating the "all goto's are evil" mindset, just remember:

"A foolish consistency is the hobgoblin of small minds."

Doing something for a good reason=good.
Doing something because it's the rule=bad.

Which comes back to one of the rites of passage to becoming a good programmer - when you move beyond the "how" of things and start to understand the "why"

Philo

Philo
Wednesday, May 21, 2003

Jesus. Do these people also go around retro-actively applying all the other latest coding standards as well?


Wednesday, May 21, 2003

My very first professional job was involved with porting an existing running COBOL accounting system onto a Northern Telecom Data 100 (dual 8085 processor and 10Mb Winchester and a tape cartridge drive that stuck up in an angle at the top which earned it the soubriquet K9).

As was common at the time the COBOL was implemented for the particular architecture, especially the screen handling.  The existing application had an On Unit in every module which managed the cursor with a deeply nested set of IFs and GOTOs.

So as a side issue (given my newly forged structured programming techniques), I investigated unwinding all that logic and replacing it with the machine specific Screen handling.  The guy that ran that part of the company (and my boss) saw me one evening and was horrified.  Now horrified was a bad reaction (there was a lot of NIH), but his question was the right one.

'Is it broken?'

And of course it wasn't.

Simon Lucy
Wednesday, May 21, 2003

I think that the "all goto's are evil" mindset is a remnant from times when people used "goto" statement for looping and "for" and "while" statements were relatively unknown.

The famous "Go To Statement Condidered Harmful" paper was written in 1968. That is 35 years ago.

Nowadays nobody would use "goto" statement for looping. Everyone uses "for" or "while" statement.

The goto haters have won the war but they fail to recognize it.

jannek
Wednesday, May 21, 2003

Actually using goto for cleanup is one good idea, particularly if you need to guarantee the order of handle freeing. I used it occasionally in C when I had code like:

    h1=GetHandle1()
    stuff
    if (error) goto cleanup1
    stuff
    h2=GetHandle2()
    stuff
    if (error) goto cleanup2
    loadsa stuff
cleanup2:
  free memoryforstage2
  free handlesforstage2
cleanup1:
  free memoryforstage1
  free handlesforstage1

It's possible you need this less with C++ since object lifetimes can be determined by their scope, you  might want the same thing in C# as there are no guarantees that the finaliser gets called. In practice gotos can make code better than a long sequence of nested if tests and escape clauses from loops.
In general gotos are a bad construct, just some times the code is an awful lot easier to read with them.
They are however a good sign that code is complicated.

Peter Ibbotson
Wednesday, May 21, 2003

I'm afraid that I'm guitly as charged.

A few years ago I remember rewriting somebodies VB, criticising them for all the gotos.

My replacement had if statements 7 levels deep.  I wince at the memory of it.

Nowadays I find it less of an issue because I don't find myself using such tortuered functions anymore.

If you have a function that it so twisted that your better off using a goto to untangle it then the real problem is at a higher level.

Ged Byrne
Wednesday, May 21, 2003

I have ran across goto for the error handling case as in Peter's example. I don't tend to write it like that myself (or if I did, I would only have 1 clean up section, by making h1 and h2 NULL at the start, and checking for each clean up bit the value of the handle) -- but it's not so evil as to be hard to understand or broken in some way.  I wouldn't change something like this merely for the sake of changing it.

Some other examples of where I have found goto reasonable

1. In retry-code (like doing hardware stuff). 

retry:
    DoOperation1() ;
    if Operation1Failed { goto retry ; }
    DoOperation2() ;
    if Operation2Failed { goto retry ; }
    DoOperation3() ;
    if Operation3Failed { goto retry ; }
  ...etc....
    DoOperation40() ;
    if Operation40Failed { goto retry ; }

    // hey it finally worked

Some guy seems something like, and changes it to 40 Nested while loops, as Goto is evil, and while is not - at least in his head.  He also uses 4 or 5 characters to indent in nested loop which is the coding standard.  Now try reading or editing code which is 280 characters wide.... yeh this really happened.  Even the guy who changed it, couldn't tell if he had done it right.

2. Back in DOS text mode days, we used to have code which let people enter stuff in a form, Return = move to next field, tab = back.  There was a lot of stuff that was special to each field.

In later versions of these types of apps, we had a library that could handle that including all the special cases, but in the early days, a lot of code tended to look like

field1:
  Input Field1
  ProcessField1

field2:
  Input Field2
  ProcessField 2
  if (tab was pressed) goto field1 ;

field3:
  Input Field3
  ProcessField 3
  if (tab was pressed) goto field2 ;


Now, not fantastically beautiful, but reasonable understandable, even if you have a lot of fields

Now some joker, takes out goto's but uses same structure (again this happened)

do
{
do
{
  Input Field1
  ProcessField1

  Input Field2
  ProcessField 2
} while (tab was pressed)

Input Field3
ProcessField 3
} while (tab was pressed)

Except Turns out above is NOT right, as tab on 3 goes back to 1 now, so now he sets up some variable to track the current field and put if conditions round each InputField/ProcessField... and so it goes... now imagine the kludge with 100 fields....  Again the guy thought it was better (even though it was impossible to tell if it was still right) because it didn't use GOTO

S. Tanna
Wednesday, May 21, 2003

Some gotos are just masked by syntactical structures.

The switch for example, which I generally use for handling commands or parsing.  It always compiles down to a goto at the end, the syntax controlling the condition.

Simon Lucy
Wednesday, May 21, 2003

In VB routines I generally have an ERROR_HANDLER: label and an EXIT_POINT: label at the bottom of most routines.  Since the position is standardized I feel that I can use Gotos to get to those points with little fear that the maintenance programmers will get lost.

One thing I come across frequently in consulting is error handler labels that are different for each routine.  In my current project the error handlers are an abbreviation of the routine with ERR appended.  This makes the goto a little bit more confusing since it isn't always clear that something like RWS_ERR: is the error handler.

Putting goto labels in the body of a program is something that I try to avoid, but there are cases where I find it acceptable. 

Ran Whittle
Wednesday, May 21, 2003

"It's all goto's in the end" is kind of a lame comment.  I'm not aware of a processor with a WHL instruction.  The only reason case would be any thinner a construct over goto is because it uses labels, and the fall-through semantics make more like a goto than other control statements.

And it is that similarity to goto that lets it be abused thusly:

    send(to, from, count)
    register short *to, *from;
    register count;
    {
        register n=(count+7)/8;
        switch(count%8){
        case 0:    do{    *to = *from++;
        case 7:        *to = *from++;
        case 6:        *to = *from++;
        case 5:        *to = *from++;
        case 4:        *to = *from++;
        case 3:        *to = *from++;
        case 2:        *to = *from++;
        case 1:        *to = *from++;
            }while(--n>0);
        }
    }

Which I think can be described as evil-genius code. see http://www.lysator.liu.se/c/duffs-device.html for details about it.

Keith Wright
Wednesday, May 21, 2003

Is goto any more evil than continue and break?

For example, the retry example above, I would probably have written:

while(1) {

DoOp1();
if (failed) continue;

DoOp2();
if (failed) continue;

...

DoOp40();
if (failed) continue;

/* Ah, done at last */
break;

}

cdavies
Wednesday, May 21, 2003

Yes but the drop through accumulative nature of the case/switch can be useful.

It can also be an easy hole in the ground if someone later doesn't understand the implication of a missing break.

Simon Lucy
Wednesday, May 21, 2003

I think the reason GOTO was considered evil was that it could, and apparently was, used to transfer execution from inside deeply nested branches to anywhere by line number.

This could include earlier, or even into other nested branches. Imagine the mess.

This made it impossible to break programs into packages, for analysis or upgrading.

echidna
Wednesday, May 21, 2003

"Every time I have encountered a goto in production enviroment it has been in twisted pile of crap hacked together by an incompetent."

Yup.  In fact, I'm very thankful GOTO exists in C++, as it makes it much easier for me to spot "Hacky Hackmaster" code.

Look, I don't know if GOTO is intrinsically bad or not (personally, I think it's almost always bad).  But I know for a fact that when I see a GOTO in MFC/C++ code, it was written by a hack, and I'd better seriously refactor it.  Usually I find a bug or two, as well.

Has anyone pointed how that it's really hard to keep resources from leaking when you have crap like GOTOs, multiple returns, etc.?

Spaghetti Rustler
Wednesday, May 21, 2003

Ahhhh MFC...

I think you'll find a few naked gotos in there.

Simon Lucy
Wednesday, May 21, 2003

The GOTO is easily removed by using a status flag.

--- Old code ---

if(condition is good)
do stuff
else
goto cleanup
end if

if(condition is still good)
do stuff
else
goto cleanup
end if

cleanup:
do cleanup stuff

--- End of old code ---


--- New Code ---

if (condition is good)
    do stuff
else
    cleanup = TRUE
end if

if(condition is still good)
    do stuff
else
    cleanup = TRUE
end if

if (cleanup = TRUE)
    do cleanup stuff
end if

--- End of new code ---


It's trivial.  I've coded this way for years.  It's even mentioned in Code Complete by Steve C.

AJS
Wednesday, May 21, 2003

continue, break, multiple returns from a function.  All so-called "bad" programming, all like a concealed goto... But not nearly so much fanaticism about them.  Why?

S. Tanna
Wednesday, May 21, 2003

Dykstra's article on the Goto covered the reasons why he felt the goto was harmful. See: http://www.thocp.net/biographies/papers/goto_considered_harmful.htm

The problem was goto's allowed the creation of programs that were hard/impossible to understand, because you could not break the program into pieces and just study that piece.  Spagetti code was a program that had no structure at all, sort of a stream of consciousness program. (Imagine 1,000 lines of code with no subroutines using gotos to build loops and if tests.) So the problem is not the goto but the fact that goto's allow us to write terrible code. Goto's can be used safely, but it requires discipline and it requires that everyone understand how they are being used.

Consider these examples

if (x >= y) goto a:;
x=x+2;
goto b:
a:
x=0;
b:

and

if (x <y)
  x=x+2;
else
  x=0;

The two samples are equivalent, in fact, the if else is compiled into code similar to the goto code. If a goto is just used like this it is "safe" but the problem is that there could be another "goto a:" in the program. Without examining the entire program there is no way to know if it is safe to change the goto code. This need to know the entire program was what made the goto harmful.

The important thing is to write code that is modular and can be easily understood by others. 

John McQuilling
Wednesday, May 21, 2003


Truly evil would be the cobol ALTER statement - it allows you to change at runtime the destination of a GO TO.

Joe AA
Wednesday, May 21, 2003

Sounds like a teamwork problem.  Unit tests can be used to make sure some simian doesn't break your goto-laden code while refactoring.

The example about gotos making errors easier to handle seems spurious because many languages can handle them with mechanisms like exceptions, labelled breaks, continue etc.  My C is extremely rusty, but if all it offers is goto for these purposes, then all you can do is have strongly-worded comments about how to respect your gotos.

What sucks is that I'm getting into writing interpreters, and I really would like gotos occasionally.

Tj
Wednesday, May 21, 2003

A Cobol programmer told me some 5 years ago that GoTo is not bad, as long as it only jumps forward in code. I think he has a point.

Thomas Eyde
Wednesday, May 21, 2003

"The GOTO is easily removed by using a status flag."

entirely not the point :)

your example was perfectly good code (thats how I choose to do things myself)
But OTOH the cleanup example using goto was *also* perfectly good clean code.
So why bother to change it at all?


<g> besides, Im also very distrustful of people whose first inclination when they hit a special case is to 'use a status flag'.....Ive refactored code that has had up to 13 status flags, the combination of which decided what was going to happen.
The problem is that when the first special case appears in a patch of code, using a status flag is a perfectly reasonable solution and refactoring the lot is usually overkill, with each further special case discovered the argument tips more and more toward refactoring and less and less to using YASF (yet another status flag)..IMO the balance usually tips approx when a third status flag is found to be needed..

FullNameRequired
Wednesday, May 21, 2003

Someone above wrote:

>1. In retry-code (like doing hardware stuff).
>
>retry:
>    DoOperation1() ;
>    if Operation1Failed { goto retry ; }
>    DoOperation2() ;
>    if Operation2Failed { goto retry ; }
>    DoOperation3() ;
>    if Operation3Failed { goto retry ; }
>  ...etc....
>    DoOperation40() ;
>    if Operation40Failed { goto retry ; }
>
>    // hey it finally worked

They observed that doing it as a while would require 40 nested whiles.

That isn't true.

bool NotDone = true;
while (NotDone)
{
  DoOperation1()
  if (Operation1Failed)
    continue;
  DoOperation2()
  if (Operation2Failed)
    continue;
  ....
  DoOperation40()
  if (Operation40Failed)
    continue;
  NotDone = false;
}

Gotos aren't necessary.  Both versions are equally understandable.  I agree that it wouldn't be worth changing in code that already worked properly.

Anonymous
Wednesday, May 21, 2003

Ummm, remind me what a continue is...

Oh, yep its a non-conditional branch to the test of a loop.  Smells like a goto to me. 

Which isn't a bad thing, I use continue a lot when I have to and its usually safe if its wrapped in a conditional branch but if a function is also called you've basically got non-provable code. 

But then everything is a risk, even if everything isn't a goto.

Simon Lucy
Wednesday, May 21, 2003

Goto is a very powerful statement. That power is what makes it dangerous. Unrestricted use of goto results in the things we've always complained about.

So, under what circumstances are gotos acceptable? I would suggest the following:

Goto is a tool that should be used to create new control structures. It should not be used on it's own.

So, for example, the "goto cleanup" construct is actually being used to simulate stack unwinding and exception handling. This is a good thing.

Similarly, the "goto retry" example above is simulating a continue statement. However, in this case, the language already HAS a valid control structure - the continue keyword. You shouldn't use goto to simulate the things that are already in the language. Continue is limited to being within loops, and only affects the innermost loop. As such, it is safer to use and more expressive in the code. You don't have to guess where the continue is going; with a goto it *could* go anywhere.

Chris Tavares
Wednesday, May 21, 2003

I sometimes do:

class LoopBreakException {}

try {

  if(!Operation1())
      throw new LoopBreakException();

  if(!Operation2())
      throw new LoopBreakException();

  ...

} catch(LoopBreakException e) {
} finally {
  // clean up
}

Andrew Reid
Wednesday, May 21, 2003

Chris makes an important point.  In my opinion, continue is preferable to goto even though they can be used in the same way, precisely because continue is less powerful.  That goto could go anywhere in your program, and is can be more difficult to follow.  continue, on the other hand, has well understood semantics, and more importantly a very limited scope.

However, that's talking about designing such a loop from scratch.  I certainly don't think that's an example of gotos that should be removed from working code

Mike McNertney
Wednesday, May 21, 2003

Actually this is not a bad challenge. Here are GOTO usages that gave it a bad name:

LINE 12 -- Doing who knows what

Handling a student record
- Processing variable one
- - Found special condition
- - - Checking different values
- - - - if value == 26 GOTO LINE 305
- - - - if value == 51 GOTO LINE 389
- - if on Dean's List GlobalVar=TRUE GOTO LINE 12

Formatting a letter to student
- Deciding reason and format
LINE 305 - - We'll do this case here
- - Other stuff
LINE 389 - - Now do the case for other thing
- -

echidna
Wednesday, May 21, 2003

Ah, the power of GOTO, now longer used for coding but to prop up endless discussions.

The problem was solved even before I got my TI-99/4a.

If your code has GOTOs and it works, leave it.  For new code, don't write GOTOs.

But what about error handling, I hear you say.  Handle errors inline as much as possible.  Easier with VB.NET try/catch/finally, but achieveable in VB with RESUME NEXT.

Besides, for a OOP language, whats wrong with Err.On & Err.Off?

Err.On


If your code has 13 status flags (presumably T/F ones), then it sounds like a good target for refactoring.

C programmers don't like the BASIC Select Case statement, because it doesn't automatically 'fall thru' to the next case.  I think even K&R commented that the way it works in C is 'probably a bad idea'.



Now, an evil GOTO is this - GOTO A, where A is a variable, hopefully containing a valid line number.  (GOSUB A works too).  Older folk will have encounter BASICs that support this.  I remember being upset that newer versions lacked this capability, but I got better.

This is a pale imitation of the assember version, Jump Relative.  JR 5 jump 5 lines down, JR -5 jump 5 lines up, and JR 0 hangs your machine.  Inserting or deleting lines will change the target line.  Enjoy debugging that.

do stuff
Thursday, May 22, 2003

(Grr, inconsistent UI... I curse you, TAB key :-)


Ah, the power of GOTO, now longer used for coding but to prop up endless discussions.

The problem was solved even before I got my TI-99/4a.

If your code has GOTOs and it works, leave it.  For new code, don't write GOTOs.

But what about error handling, I hear you say.  Handle errors inline as much as possible.  Easier with VB.NET try/catch/finally, but achieveable in VB with RESUME NEXT.

Besides, for a OOP language, whats wrong with Err.On & Err.Off?

Err.On
  do stuff
Err.Off
If Err.Number <> 0 then ...

If your code has 13 status flags (presumably T/F ones), then it sounds like a good target for refactoring.

C programmers don't like the BASIC Select Case statement, because it doesn't automatically 'fall thru' to the next case.  I think even K&R commented that the way it works in C is 'probably a bad idea'.

Now, an evil GOTO is this - GOTO A, where A is a variable, hopefully containing a valid line number.  (GOSUB A works too).  Older folk will have encounter BASICs that support this.  I remember being upset that newer versions lacked this capability, but I got better.

This is a pale imitation of the assember version, Jump Relative.  JR 5 jump 5 lines down, JR -5 jump 5 lines up, and JR 0 hangs your machine.  Inserting or deleting lines will change the target line.  Enjoy debugging that.

AJS
Thursday, May 22, 2003

All my VB books have "OnError GoTo2 statements. As the GoTo is within a private sub or function then you can't go very far.

If the sub or funtion is long enough for you to get lost, then the problem is not with the GoTo but with the length of the function or sub.

Stephen Jones
Thursday, May 22, 2003

Have to respectfully disagree with the idea of using Inline error handling as the default in VB.  Inline can work with Expected errors, but with unexpected errors you will need some sort of reporting system so that you can track it down.  You cannot do this without centralizing the error handling.

Ran Whittle
Thursday, May 22, 2003

Yea! See your point!

What I need is "onError GoTo somebody who knows what the hell is happening" code.

Stephen Jones
Thursday, May 22, 2003

Unexpected errors.

"Error 552323552.  Vogon construction fleet approaching.  Destruction of Earth imminent.  Abort, Retry, Cancel".

Now that's an unexpected error message.

It was mentioned that all VB books talk about On Error Goto.  The good ones cringe while doing so - 'By all means use, but try not to'.  Remember Sturgeons Law - 90% of everything is crud.

On Error Goto gets used because there isn't much else.  That's not a really good defense.  Centralised errors handling is the programmer Holy Grail - you'll never find it.

If you throw in an error trap to catch an unexpected error, you haven't thought it thru.  There are a limited number of errors (I've got a list) and only a few apply to each line of code.

A = B / C will not generate 'Disk full' errors.  And what exactly are you going to do about it if it does?

I have functions containing a single line of code, and 50 line for error handling after it.  Much of my code is 'unprotected', those areas that can generate errors are shuffled off into their own playground.  Does the unprotected code have bugs?  Absolutely.  And when it fails, I want to know, rather than having a buggy error handler hide it.  (That's where most bugs are!)

Then have test cases running against it non stop.  Not perfect, but better than nothing.  Got an encryption routine?  Run it against every file on your system, including temp & garbage files.  Do it in directory order, then date order, then by size, etc.  Internet cache has wonderful stuff at time.  Then create files based on the sizes of these files, nice weird hopefully random stuff.

Having said that, unexpected errors will happen when OS or language versions change.  Hello DLL hell.  VB string handling differs between versions.  You write test cases for the code you write, but how many of you write test cases for the native functions?  Your error handling may hide these.

An unexpected error is one you can't handle.  So why handle it?  Not trying to provoke, but if you grab new OS versions before your customers do (Win beta testing), you'll see 'Unexpected error in whatever', but your customers never will.

Program crashes are annoying.  Sugar coating makes it worse (personal opinion).  'I'm sorry, something went wrong, so I'm going to shut down now'.  Still not happy.

A quick quiz:

This line of code is pretty much guaranteed to run in 99.999% of cases.  There is one obvious flaw, a couple of not so obvious, and a few 'but that's cheating' flaws.

A = B / C

How many errors?  And do you prevent them or trap them?

AJS
Thursday, May 22, 2003

You must prevent whatever you can, obviously, but unexpected errors are a fact of life.  If a=b/c were to somehow create a disk full error I would want an error handler to log the error and inform the user (with absolutely as much  sugarcoating on the dialog box as possible).  I also would need to make sure that any resources that were in use were properly released or otherwise handled.

We cannot have a situation where the user is given the raw VBA runtime error dialog, where s/he then presses the END button.  And we should not have a situation where an error occurs without leaving any clues behind so that a maintenance programmer has nothing to follow up on when pursuing a fix.

Every project that I have ever done has managed to achieve this level of control.  It is not unattainable.  100% foresight into all possible points of failure, however, will never happen.

Ran Whittle
Thursday, May 22, 2003

As odd as it may seem, my current project is programming a microcontroller to run a microwave oven.

Lots of GOTOs, but they're called JMPs, so it doesn't count!

In the production code, I can't log errors, and I can't complain to the user either.  It's a microwave.  Just cook my dinner, damn it.  My only option is to anticipate all errors, and just make it work.

I get rudimentry error handling, but it's not enough to get most people excited.

I also work in environments where error handling does not even exist - there are no run-time errors that stop the system.  Crashes do not happen.  Period.  Divide by 0, disk full, no worries.  Open, read and close non-existent files, again, no worries.  These are systems handling thousands of telephone calls - they have to work, and you code & test them very carefully.  Callers to not want do reboot (hang-up & re-dial) under any circumstances.

I feel that error handling is like optimisation - you only need to look at the 10% cause problems.

Wrapping error handlers around all your code (production, not dev or beta) does not solve your problem.

I'm tired of reading error logs.  I've seen bug databases full of logged errors - most unsolved.

Joel even mentions it, do you fix the bug that happens when you run 256 colour Win 95?  The O/S2 guys problem?  Maybe...

If A = B / C causes a 'Disk Full' error, I'd blame cosmic rays and forget it.  Now if it does it TWICE...

AJS
Thursday, May 22, 2003

As I was typing the last post I was thinking that this really is a function of the environment you are working in.  We agree on that.

I write (and to a lesser extent, maintain) desktop applications, mostly in VB/VBA.  The desktop could be anywhere in the world, and unexpected errors are usually errors thrown by other applications that I am scripting.  User accounts are usually pretty dodgy, so the error log is often the only solid lead I get as to the cause of the error.  And, since it is in front of an end user, sugar coating the error dialog is important.  For a server app it would not be so important.

I agree with you that I wouldn't want an error log in my microwave either.

Ran Whittle
Thursday, May 22, 2003

> Centralised errors handling is the programmer Holy Grail -
> you'll never find it.

There are some languages (e.g., Delphi; not sure about C++) that allow you to create your own default exception handler.

What this means is that unhandled exceptions will eventually go up the exception stack, until they reach the default exception handler. Since you've created your own, you now have a central point for handling all exceptions you didn't catch elsewhere.

Paulo Caetano
Friday, May 23, 2003

Good point, your enviroment does play a major part.  Excel is particuarly exciting when it comes to errors and weird stuff.

Generally, if a function fails, it because it was passed bad data.  Eliminate the source of bad data.  Errors go away, so does the need to handle them.  (Ok, real world is not that simple)

Bonehead example - today at work.

    On Error Goto ErrHandler
    Open "file.txt" for input
      Line input A$
    Close

    exit sub

  ErrHandler:
    'oops, missing file, create it
    Open "file.txt" for output
    Close
    Open "file.txt" for Input
    Resume Next


Typical valid VB code.  Rewritten to...

    If FileExists("file.txt") = False then
      'oops, missing, create file
      Open "file.txt" for output
      Close
    end if

    Open "file.txt" for input
    etc

No error handling.  Nitpickers will point out that the line to create a file can fail, eg if Disk Full, and cause a crash.  True, in the real world it is abstacted away - CreateFile("file.txt").  Look at the first example, this error happens IN THE ERROR HANDLER!

I've only come across one book that describe coding like I do, highly recommended.

Visual Basic 6: Error Coding and Layering - Tyson Gill.  Amazon have it - http://www.amazon.com/exec/obidos/tg/detail/-/0130172278/ - hmm, I see he has a new book.

I picked up the tip to write test cases for for native functions (eg Len, Format, Abs) from this book.

The negative reviews are very revealing - the Linux quote is great, the 'but he doesn't tell me how to write an error log' one if far better.  These people are looking for a silver bullet to slay their apps, as well as not realising it is not a 'Learn VB' book, it about architecture.

AJS
Friday, May 23, 2003

Bugs in A = B / C, if anyone is still here!

Fails if C is 0.  (I have seen an environment where A is set to 0 instead of an error happening)

Rounding errors.  A = .33333 if B = 1 and C = 3.  A * 3 is not 1, it is .99999.  Check your bank balance!

Overflow errors.  A is an INT, B & C are Longs.

C is probably defined as a string.

And it is probably empty.

Not a valid assember statement.  (Very common if you use multiple languages)

AJS
Friday, May 23, 2003

Regarding centralised error handling, my point is once the handler gets informed of the error, then what?

The 'Disk Full' or 'Type mismatch' error has floated 40 levels up the call stack, how does it fix it?

What benefit is there to the user?

Microcontrollers contain watchdog timers, if you don't reset them regularly a reboot occurs.  All the centralised handler can do is shut down the program, and restart.  Nobody likes watchdog timers much because they hide the problem, rather than solve it, and who knows what state the chip is in...

AJS
Friday, May 23, 2003

"I'm not aware of a processor with a WHL instruction." - Keith Wright

I'd argue that the JCXZ instruction of the x86 processors, the DJNZ instruction of the 80196, and the DBcc instructions of the 68k family are "while" instructions to the same extent that a conditional branch instruction corresponds to an "if" statement.

Steve Wheeler
Friday, May 23, 2003

Benefit to user differs by environment.  With a microwave oven it is no help.  In the bank where I work it means that when a user complains that s/he needs to do Something that requires they follow steps 1,2, and 3.  If those steps cause an error I can track the error when they report it.  I can help find a workaround, or, if possible, patch the application.  For desktop apps you need this.

it also means that other open resources further up the call stack can be released and others that were about to be used will not be.  Remember we are talking about VB here.  You are probably not creating objects but rather using other peoples objects.  They need to be restored to their idle state.  If the error doesn't pass up the call stack how will that happen?

RE: A=B/C
Also, if C can be a decimal, then A can easily overflow regardless of what it is. 

Ran Whittle
Friday, May 23, 2003

Returning after a quick vacation.

The retry example, if done in C, could be done using continue etc... but if I remember right was an early version of Turbo Pascal, which I don't think had continue or break

Frankly I think the person who commented on designing from scratch vs maintaining existing code, hit the nail on the head.  If the code is okay, readable, works, but isn't your personal stylistic preference, why change it?

S. Tanna
Monday, May 26, 2003

*  Recent Topics

*  Fog Creek Home