The Transgressive Manifesto is quite short:
It's okay to useThe single underlying principle is that we value willful controversy over mindless conformity.
I do have a serious point here. Even programmers who haven't read the original article (because they can't spell Dijkstra and so can't find it through Google) know that
GOTOs are "considered harmful". But as Marshall and Webber point out, "the problem lies ... in the loss of knowledge and experience. If something is forbidden for long enough, it becomes difficult to resurrect the knowledge of how to use it."
How many Oracle developers even realise PL/SQL supports
GOTO? It does, of course. Why wouldn't it? PL/SQL is a proper programming language.
The standard objection is that there is no role for
GOTO because PL/SQL has loops, procedures,
CASE, etc. But sometimes we need to explicitly transfer control. In recent times I have have across these examples:
- a loop which raised a user-defined exception to skip to the
END LOOP;point when the data was in certain ststes, thus avoiding large chunk of processing. A
GOTOwould have have been cleaner, because it is poor practice to represent normal business states as exceptions.
- a huge function with more than a dozen separate
GOTOs directing flow to a single
RETURNcall would have been really helpful, because I needed to log the returned value.
- a condition which set a counter variable to a large number so as to short-circuit a loop. Here a
GOTOwould simply have been more honest.
GOTOwould have redeemed a function with 800 LOC ; clearly there'e a lot more refactoring to be done there. But it would have been better.
Here is a situation I have come across a few times. The spec is to implement a series of searches of increasing coarseness, depending on which arguments are passed; the users want the most focused set of records available, so once a specific search gets some hits we don't need to run the more general searches.
IF statements provide one way to do this:
result_set := sieve_1(p1=>var1, p2=>var2, p3=>var4, p4=>var5); if result_set.count() = 0 then result_set := sieve_2(p1=>var2, p2=>var3, p3=>var4); if result_set.count() = 0 then result_set := sieve_3(p1=>var3, p2=>var5); if result_set.count() = 0 then .... end if; end if; end if; return result_set;Obviously as the number of distinct searches increases the nested indentation drives the code towards the right-hand side of the page. Here is an alternative implementation which breaks the taboo and does away with the tabs.
result_set := sieve_1(p1=>var1, p2=>var2, p3=>var4, p4=>var5); if result_set.count() > 0 then goto return_point; end if; result_set := sieve_2(p1=>var2, p2=>var3, p3=>var4); if result_set.count() > 0 then goto return_point; end if; result_set := sieve_3(p1=>var3, p2=>var5); if result_set.count() > 0 then goto return_point; end if; ... << return_point >> return result_set;I think the second version has a clearer expression of intent. Did we find any records? Yes we did, job's a good'un, let's crack on.
GOTO: not as evil as triggers.