The Debate on Code Simplification: What's the Verdict?

  • Thread starter bomba923
  • Start date
  • Tags
    Code
In summary, most people find goto usage questionable. They are hard to justify and can be replaced with more simple alternatives.
  • #1
bomba923
763
0
Some find it alright if it simplifies code, while others deem it absolutely unacceptable.

So what's the general consensus regarding their use?
 
Last edited:
Technology news on Phys.org
  • #2
You have heard of Djikstra, haven't you?

A goto can be preferable to alternatives in some cases:
  • handling of exceptional cases, particularly in a language such as C
  • breaking out of a deeply-nested loop
  • complying with a rigid "single point of return" rule.

With the exception of one year on a project where the manager was a single point of return1 nazi, I have used very few goto statements per decade for the last three decades. They are hard to justify. In a project with code reviews, the user of a goto had better be very prepared for the inevitable broadside attack. Nearly every use of the goto can be eliminated with appropriate use of if/then statements and some boolean algebra. The justification is that the cure (the extra nesting and extra logic) is worse than the disease (the goto statement, of course).

1 The ugly code and the use of gotos that inherently and inevitable results from making "single point of return" a dictum is, to me, proof that applying this guideline as a hard-and-fast rule is wrongheaded.
 
  • #3
These days you just use exceptions which are merely gotos with a much more complicated syntax.
 
  • #4
my boss use lots of goto and his code is unreadable !
If you are working in a team, or your code will be read by someone else, avoid using it.
 
  • #5
Not all languages support exceptions, and not all projects allow their use.
 
  • #6
Burnsys said:
my boss use lots of goto and his code is unreadable !
If you are working in a team, or your code will be read by someone else, avoid using it.

The goto has been viewed as evil since 1968 (or before) and in almost all cases is not needed. Your boss needs to read Djikstra's paper.
 
  • #7
The reason he's a single-point-of-return nazi is:

Static code metric analysis software that determines McCabe's cyclomatic complexity value, goes 'beserk' over a lot of embedded returns. Shying away from good code management practices which require a lot of effort, managers in large companies opt for this kind of software which just spews out Halstead numbers and complexity values.
It's easy to look at '42' and say 'it's over 41. fix it'

Your manager probably came from an environment like that. Or maybe he's creating one.
Metric software has a place, but it shouldn't be God.
 
  • #8
In C, you can usually replace a simple clear goto statement with half a dozen convoluted breaks, continues, and at least 10 local variables with confusing names to keep track of incomprehensible logical conditions, if your local programming guru says "gotos are always bad".

There's a technical term for this. It's called "revenge".
 
  • #9
Code analyzers shouldn't go beserk over a return or goto. A return statement (or a goto) should not change the cyclomatic complexity of a function at all. It is the if statement wrapped around the return or goto that bumps the complexity. I have used many tools that count incorrectly. Perhap your management uses such a tool? (Example: simple straight line code should have a cyclomatic complexity of 1; many tools report this as zero so the complexity values for multiple functions can be added.)

Actually, this manager came from an environment where unfetterred use of embedded return statements caused resource problems (e.g., leaks). He carried that experience over and mandated single point of return.

Regarding metrics, they certainly do have their place. Fixing a function with a cyclomatic complexity of 42 sounds reasonable: How would you verify/validate such a beast? I have always viewed Halstead's metrics as a bit suspect. Anything that has to use "thoughts per second" as a scale factor (actually, "mentations per second") has to be a bit dubious.
 
  • #10
A goto should be used whenever it makes the code easier to read!

Typically, this involves making the code most resemble the algorithm you're trying to implement. Another circumstance that hasn't been mentioned is when you have code that should only be executed when your loop finishes normally:
Code:
for(p = 2; p*p <= N; ++p) {
if(N % p == 0) { goto found_factor; }
}
printf("N is prime!");
found_factor:
// continue along

(Compile-time) state machines are another good candidate for using goto's.
 
  • #11
D H said:
Not all languages support exceptions, and not all projects allow their use.
I was trying to be funny - to avoid the simple "goto error:" in the middle of a complex loop we now have exceptions which are exactly the same thing only more confusing.

Alephzero put it much better - I have suffered code where every statement was surrounded by layers of " if (bStatus) " to avoid having a goto.
 
  • #12
DH - cyclomatic complexity is very much affected by return statements. It increases cyclomatic complexity. Period. Argue with Tom McCabe, not me. 'berserk' is my term to indicate what I personally think is an over-reaction.
 
  • #13
mgb_phys said:
I was trying to be funny - to avoid the simple "goto error:" in the middle of a complex loop we now have exceptions which are exactly the same thing only more confusing.

I see, and I agree. Wrapping a bunch of code in a try/throw/catch pile of complexity to avoid a simple and obvious "goto error", is taking the "gotos are evil" one step too far. One of my firmest rules of programming is that unyielding rules are evil. :biggrin:
 
  • #14
D H said:
I see, and I agree. Wrapping a bunch of code in a try/throw/catch pile of complexity to avoid a simple and obvious "goto error",

I always thought that 'throw' should be called 'not_a_goto_honest' :biggrin:
 
  • #15
... and catch should be called 'come_from'.
 
  • #16
Hurkyl said:
A goto should be used whenever it makes the code easier to read!

Typically, this involves making the code most resemble the algorithm you're trying to implement. Another circumstance that hasn't been mentioned is when you have code that should only be executed when your loop finishes normally:
Code:
for(p = 2; p*p <= N; ++p) {
if(N % p == 0) { goto found_factor; }
}
printf("N is prime!");
found_factor:
// continue along

(Compile-time) state machines are another good candidate for using goto's.

Which could be argued about, since the code after found_factor will still be executed after printing the "N is prime" message.

I'd write
Code:
for(p = 2; p*p <= N; ++p) {
if(N % p == 0) { found_factor = true; break; }
}
if (!found_factor) { printf("N is prime!"); }
// continue along
or, if there is more extensive code than a print, even something like
Code:
void found_factor(int factor) {
  printf("N is not prime, it has %d as a factor", factor);
}

for(p = 2; p*p <= N; ++p) {
if(N % p == 0) { found_factor(p); break; }
}
// continue along

(Long time no programming C, so not responsible for syntax errors :smile: - you get the point)
 
  • #17
mgb_phys said:
These days you just use exceptions which are merely gotos with a much more complicated syntax.

Exception propagation in C++ does stack unwinding. I didn't think goto did that.

Real programmers use "comefrom".
 
  • #18
nmtim said:
Exception propagation in C++ does stack unwinding. I didn't think goto did that.

Real programmers use "comefrom".


I thought real programmers used setjmp() and longjmp(). :)
 
  • #19
jim mcnamara said:
I thought real programmers used setjmp() and longjmp(). :)

No - real programmers modify the executable image on the fly
 
  • #20
Why is it that multple return's are acceptable, but not even one goto? Essentially, they're almost the same, causing a break in the stream of code flow.

Regarding the comment about goto's losing popularity back in 1968, that's hard to believe considering all the Fortran programming still going on at that time.

I guess the perspective on goto's is different for us old guys that were programming back in the 1960's (1968 for me) and 1970's before there was an "anti-goto" mystique, similar to motorcyclists from the 1960's when British bikes where better than Harleys, or 1970's when Japanese bikes were better than both and not shunned, I never got the "Harley" mystique.

Regarding this:
Code:
for(p = 2; p*p <= N; ++p) {
if(N % p == 0) { found_factor = true; break; }
}
if (!found_factor) { printf("N is prime!"); }
else{...}
// continue along

Being old school, I have a problem whenever the same descision is made twice in program (one extra "if" and a varible used to avoid a goto), which goes along with the fewer the number "if" statements, the better the program.

In the situation where failure in a step stops the flow of a series of steps, I prefer "goto" to setting a status variable and constantly checking "if(status == good){ ... continue}", since you have to search the code to find if or where the first sequence that isn't conditional on "status == good". Worse yet is the nested "if{...if{...if{...}else{...}}else{...}}else{...}" where the code to handle the other branch from the first if is as far as possible from the original "if".

Sometimes a goto is just more readable, especially when used for exception conditions.

if(exception_condition == TRUE)goto xyz;

I prefer to have the main flow of a routine to not appear as conditionalized such as the if(status == GOOD){ ... conditionalized, indented, but otherwise main flow of code ...}

Sometimes the action for a test is deferred, the test is done at one point, and the action is done at a later point in the code (or maybe in several places later in the code). I liked Fortran's computed goto for dealing with these cases. For C, I use functions, and pointers to functions to accomplish essentially the same thing, setting one or more pointer to functions based on a condition that sets the "state" of a following sequence of code. If C had pointers to labels in code, it would accomplish the same thing as Fortran's computed goto. Granted that this is rare, but it is somewhat common practice to use a set of pointers to functions to represent the state of a program.

mgb_phys said:
No - real programmers modify the executable image on the fly
Fortan has computed gotos, and C has pointers to functions, close enough. IBM's mainframes include an machine laungauge instruction "Execute" that adds a third register based parameter to an otherwise two parameter instruction, which is close to modifying executable code.
 
Last edited:
  • #21
It's a repeating story - clever guy writes a well reasoned argument commenting on one aspect of programming. People who read the title but not the essay turn it into an absolute rule. People who have read it are faced with either argueing the case with idiots or simply giving in and not using the feature. Eventually the feature is reinvented in a new form which is even more of a problem than the original.

The same thing applies to Fred Brook's "adding manpower arguement" in mythical man month.
 
  • #22
Jeff Reid said:
mgb_phys said:
No - real programmers modify the executable image on the fly
Fortan has computed gotos, and C has pointers to functions, close enough. IBM's mainframes include an machine laungauge instruction "Execute" that adds a third register based parameter to an otherwise two parameter instruction, which is close to modifying executable code.
None of these are even close. The machine instructions offer a very, very limited sense of what mgb_phys is talking about. You have to program in Lisp or something like it to truly understand the incredible power that results when a program can literally modify itself on the fly.
 
  • #23
Or you can do it in 'C' if you aren't careful about where the buffers end :biggrin:
 
  • #24
mgb_phys said:
No - real programmers modify the executable image on the fly
Well when the instruction cache on Intel CPU's started ignoring changes to memory that were already cached, it doomed all of the "real programmers". Back in the old days of assembly language programming on older computers, I was stuffing the address fields of jump and call instructions which was similar to Fortran's computed goto and C's pointer to functions which is why I mentioned them. When pinching cycles on old 8 bit cpu's helped, I was modding interrupt vector addresses to avoid using a modded jump and save a few cycles. Then there was the method of unfolding a loop for a routine by generating a sequence of instructions during initialization, and stuffing a return at the right spot for the loop count then restoring that spot after a call.

Remember the days when "inclusive or" was called "selective set", "exclusive or" was called "selective complement", and "and" with an inverted input was called "selective clear", and no one complained about "goto"?

Then again, this is how real programmers programmed back in the good ol days, before code could self modify or before there were goto's:

plugboard1.jpg

plugboard2.jpg

Now it's only the uber virus and worm authors that do any real self modifying code.
 
Last edited:
  • #25
CompuChip said:
Which could be argued about, since the code after found_factor will still be executed after printing the "N is prime" message.

I'd write
Code:
for(p = 2; p*p <= N; ++p) {
if(N % p == 0) { found_factor = true; break; }
}
if (!found_factor) { printf("N is prime!"); }
// continue along
But like I said, it depends on the algorithm you're trying to implement. If your algorithm is most naturally stated as "find a factor, and then do other stuff", and primality is an exceptional case, then the goto best reflects the actual algorithm, and it's what I would use in my code without hesitation.

But if primality was normal behavior, then I would consider writing it as you did. The choice isn't automatic because of the extra complexity and verbosity of what you wrote.



or, if there is more extensive code than a print, even something like
Code:
void found_factor(int factor) {
  printf("N is not prime, it has %d as a factor", factor);
}

for(p = 2; p*p <= N; ++p) {
if(N % p == 0) { found_factor(p); break; }
}
// continue along
And this is certainly wrong! This form only accommodates exceptional behavior when the loop terminates via the break, and does not allow exceptional behavior when the loop terminates normally.
 
  • #26
nmtim said:
Exception propagation in C++ does stack unwinding. I didn't think goto did that.

It did in Pascal, where you could have the source code of a function nested inside another function, and you could jump from inside a function to any place in the calling function.

And Pascal was designed as a language to teach people good programming habits. Hmm...

Re another post, setjmp() and longjmp() are only a quiche-eater's version of Fortran's "assigned goto", invented back in the 1950s. There is nothing much new under the sun.
 

1. What is code simplification and why is it important?

Code simplification refers to the process of streamlining and reducing the complexity of computer code. It is important because it can make code easier to understand, maintain, and debug, ultimately improving overall efficiency and productivity.

2. What are some techniques for simplifying code?

Some techniques for simplifying code include using descriptive and consistent variable names, breaking down large blocks of code into smaller functions, and removing redundant or unnecessary code.

3. Is code simplification always beneficial?

No, code simplification is not always beneficial. In some cases, overly simplified code can lead to decreased performance or functionality. Additionally, code that is too simplified may be difficult for others to understand and may not meet the specific needs of a project.

4. What are the potential drawbacks of code simplification?

Some potential drawbacks of code simplification include increased development time, decreased flexibility, and the potential for introducing bugs or errors. Additionally, simplifying code too much may make it less adaptable to future changes or updates.

5. How can one determine if code simplification is necessary for a project?

Determining if code simplification is necessary for a project depends on several factors, including the complexity of the code, the overall goals and needs of the project, and the capabilities and resources of the development team. It is important to carefully weigh the potential benefits and drawbacks before deciding if code simplification is necessary for a specific project.

Similar threads

  • Programming and Computer Science
Replies
14
Views
2K
  • Programming and Computer Science
Replies
5
Views
766
  • Programming and Computer Science
Replies
9
Views
1K
  • Programming and Computer Science
Replies
14
Views
1K
  • Programming and Computer Science
Replies
4
Views
1K
  • Programming and Computer Science
Replies
22
Views
2K
  • Programming and Computer Science
4
Replies
107
Views
5K
  • Programming and Computer Science
Replies
34
Views
2K
  • Programming and Computer Science
Replies
2
Views
1K
  • Programming and Computer Science
Replies
13
Views
1K
Back
Top