1. Computing

Goto Delphi: How I (Almost) Ended Up Using Goto in Delphi code

Is Goto that bad?

By

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.
Let's presume, at some iteration, the code is processing the "XXX\YYY\C\L" 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 then
     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 
So, what's the difference here and how come I did not think of such a usage of IFs in the first place?

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 then
     Do-Something-True
   else
     Do-Something-False
   end 
This lead me to using Goto.

The second version:

 if True then
   Do-Something-True
 end
 
 if False then
   Do-Something-False
 end 
Ok, 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?

©2014 About.com. All rights reserved.