According to the "Are you using the Goto statement in Delphi" poll, 40% of Delphi developers will be very upset if they read a sentence where Delphi and Goto and mentioned in the same context.
What's more, 40% of Delphi developers do not even know that Goto exists in Delphi!
Goto On Trial!
Goto forces the source code flow execution to be transferred to another point in the code block.In the paper "Go To Statement Considered Harmful" written way back in 1968, Dijkstra argued that unrestricted GOTO statements should removed from higher-level languages.
On the other hand, a paper by Donald Knuth "Structured Programming with Goto Statements" provides quite a few examples where GOTO may be the appropriate tool.
Back to real life. As I said when announcing the mentioned poll on the non-technical Delphi group, the first time I found myself scratching my head was when I found the reason to use a "write-only" property. A few days ago I could not avoid using the Goto statement (without making the code even harder to read), could you believe that?
How I (almost) used Goto in my 10+ years of Delphi Experience
To be honest I was amazed. Just a few days ago, I found myself opening up Delphi help to look for Goto examples and how one can use the Goto statement in Delphi. I knew Goto is here, but I never used it before!As it always happens, deadline was approaching. I had a nasty code block that needed to work "yesterday", and as much as I looked upon it ... it appeared unsolvable without the Goto, and without making the code ever more clustered by adding more helper functions - thus harder to read.
This is the situation I had to solve:
- There's a directory / folder tree.
- The code is recursively walking (processing) the folder tree.
- There's a set of countries, defined as CC = [a,b,c,d,e]
- There's a set of languages, defined as LL = [a,b,c]
- Note that LL is a subset of CC.
- A folder is a "language folder" if its name appears in LL. A folder is a "country folder" if its name appears in CC.
- Every folder needs to be processed in some way.
- Special processing is required for langauge and country folders.
- If a folder is a LL folder its PARENT MUST be a CC folder.
The problem here is that one cannot be sure if L is in LL - thus it represents a language or if it is in CC - thus represents a country. This is because LL is a subset of CC!
Of course, L might not be in LL nor in CC.
First try: using Goto !!
Here's the code I wrote, the code is using Goto.This is just a schema of the code I used. In real code, a dozen of variables are set in each condition block, objects are created, functions and procedures are being used, more if / for statements are also involved...
Note the usage of Goto, it jumps into an inner "else" block.
if L in LL then
if L.Parent in CC then
Process L as LL C as CC
else
if L in CC then GOTO skip
else
skip:
if L in CC then
Process L as CC
else
Process L as Any Other Folder
end
If a L's name matches any of the strings in LL and its parent's folder is in CC - we have found a valid CC\LL combination - where a country folder is a parent to a language folder.
If L is NOT in LL but it is in CC - L is a country folder. If L is NOT in LL nor in CC - we have an "ordinary" folder.
Is this a bad Goto usage? I cannot be sure :( Yes, I'm breaking the code flow, but am not jumping to some far away point.
Yet, the fact that this was the first time I used Goto in Delphi, I was sure some other way needs to exist to solve my problem, without code jumps.
Second try: No Goto! :)
Here's my second try:if L in LL thenSo, what's the difference here and how come I did not think of such a usage of IFs in the first place?
if L.Parent in CC then
Process L as LL C as CC
else
//add bool variable L_not_LL
Set L NOT in LL
end
if (NOT L in LL) then {if L_not_LL then}
if (L in CC) then
Process L as CC
else
Process as Any Other Folder
end
The thingy here is that, in the 99% where there is a condition to be tested, I'm accustomed to using the IF statement as:
if True thenThis lead me to using Goto.
Do-Something-True
else
Do-Something-False
end
The second version:
if True thenOk, this one is Goto-Free, but we have some strange "if" statements here. If I already tested for L in LL, why am I again testing for LL NOT in LL?
Do-Something-True
end
if False then
Do-Something-False
end

