Why is GOTO bad?
Why is GOTO bad?
Eric asks this question, suggesting that because most hardware has a JUMP instruction, that Dykstra was too hasty in denegrating it in high level languages. He then asks if perhaps BREAK and RETURN might be similar.
The short answer is NO. Dykstra wasn't hasty and BREAK and RETURN are not similar. Quite to the contrary, they are the exact opposites of JUMP or GOTO.
In my cleverly titled blog entry "Eschew ELSE" I thought I did a pretty good job of putting this question to rest. Alas, but Eric neglected to read my most excellent article on the matter and brings up the same strawman arguments again.
http://www.drdobbs.com/blog/archives/2010/02/eschew_else.html
There's a fairly simple test that can be applied to the question. Write a web server using only GOTOs (no loops, BREAK, CONTINUE, or multiple RETURN statements) and report back.
As for using BREAK, CONTINUE, and more than one RETURN, Eric trots out an example using two tests (slightly simplified):
[Please imagine that Dr Dobbs' new Blog editor allowed leading spaces and fixed width fonts.]
// Version 1 private boolean processTransaction(Transaction trans) { if (!trans.loggedIn()) return false; if (trans.sessionTimeout()) return false; completeTransaction(trans); return true; }
// Version 2 private boolean processTransaction(Transaction trans) { boolean success = false; if (trans.loggedIn()) { if (! trans.sessionTimeout()) { completeTransaction(trans); success = true; } } return success; }
He feels that version 2 is simpler because you only have to think about two tests once, while in version 1, you have think about one test twice. I think he is fooling himself. If we consider a slightly more complex example...
// Version 1 private boolean processTransaction(Transaction trans) { if (!trans.loggedIn()) return false; if (trans.sessionTimeout()) return false; if (trans.alreadyComplete()) return true; if (trans.aborted()) return false; completeTransaction(trans); return true; }
// Version 2 private boolean processTransaction(Transaction trans) { boolean success = false; if (trans.loggedIn()) { if (! trans.sessionTimeout()) { if (trans.alreadyComplete()) { success = true; } else { if (trans.aborted()) { success = false; } else { completeTransaction(trans); success = true; } } } return success; }
I can scan version 1 and know what it's doing in two seconds. I'll be you can too. Version 2 requires me to hold four tests in my head at the same time, keep track of a flag, and line up two ELSEs with their respective IFs.
I think Eric will even agree with me on this one.
-Bil

