All languages have parts that are somewhat dangerous to use. If you want to be a good programmer, you need to know what these things are for your language. But sometimes the language is chosen for you.
A long time ago, I was asked to add some features to a large program written in a version of Basic. It was not a very complex task, and I expected it to be rather straight-forward. But, alas, it was not so. For some strange reason, the program always crashed after about one hour. There seemed to be a memory leak somewhere. One thing I learned during this time was that Basic can be extremely unstructured. If you ever been unfortunate enough to have to use Basic, you may recall that the return statement can (in some versions of Basic) included a row number. This means that instead of returning to the statement after the gosub, you return to the specified row number.
1 2 3 4 5 6 7 8 9 10 |
10 gosub 500 20 print "z" rem Subroutine called from main 500 print "x" 510 return 1500 rem Subroutine used as destination in the return from previous subroutine 1500 print "y" 1510 return 10 |
In this simple example, the statement at line 20 will never be executed. Instead the return statement on line 510 will jump to line 1500. This is allowed in several versions of Basic.
This allows you to write code that is almost impossible to maintain. The gosub statements will act as goto statements since the execution flow will never return. But in this case it was even worse. For this specific version of Basic, the stack was not popped if a line number was added to the return statement. The memory leak in the program was the return addresses on the stack that were never used. In the end, the stack was full and the program crashed.
Adding the new feature to this program was easy. Rewriting it to not use line numbers in the return addresses was a lot harder since it required big changes in the structure of the program. In hindsight, it would probably have been easier to change to a version of Basic that popped the stack even if a line number was present. All other Basic version I’ve looked at do it that way.
Or, better yet, rewrite it in a completely different language….
But why I’m I bringing up this ancient example?
Every now and then, someone asks about the goto statement in C++. Some programmers feels that a goto can be used if it simplifies the structure of nested loops. I have yet to see a nested loop that can’t be refactored to be a lot simpler without the need of a goto. It is unfortunate that C++ had to support goto due to the C legacy. In this case, Java did the right thing to have goto as a reserved keyword, but it is not implemented and can not be used. In this case, there were no goto-statements, but they acted in the same way. What probably seemed like a good idea at the time this program was written, turned out to be just terribly wrong. Same thing with goto in C++. Even though it might improve the structure of the code temporarily, additional changes later on when new requirements are implemented can make the structure deteriorate in an unpredictable fashion. Better just to stay away…
Leave a Reply