Is use of GOSUB bad coding?
Goto is a shortcut. And it's a natural way of thinking. 'I'm ready here, so I Goto there'
That would be very fine, if software development wouldn't be such a complex thing.
Most of the time you don't write some code and never touch it again. Often you have to edit and reedit it again and again. And even if everything was crystal clear at first, it is very easy to loose track on what's going on in your code after some changes, because there is no clear structure with Goto's.
It's a bit like with EnableExplicit. It seems cumbersome to have to define each Variable before use, but it can really save you from a lot of trouble.
I've stopped using Goto a long time ago, and I won't touch it again just because of it's potential of getting me into trouble.
That would be very fine, if software development wouldn't be such a complex thing.
Most of the time you don't write some code and never touch it again. Often you have to edit and reedit it again and again. And even if everything was crystal clear at first, it is very easy to loose track on what's going on in your code after some changes, because there is no clear structure with Goto's.
It's a bit like with EnableExplicit. It seems cumbersome to have to define each Variable before use, but it can really save you from a lot of trouble.
I've stopped using Goto a long time ago, and I won't touch it again just because of it's potential of getting me into trouble.
Hades,
there are times when a short cut is the best method.
If you're embedded deep in loops and if..then..else..endif and case..endcase structures when it becomes clear there is no longer a point to being there, such as if an overflow occurs half way through a complex calculation, then it is easier to follow a shortcut than to follow the tortuous coding needed to exit every structure the "correct" way. It's also a lot more efficient and gives smaller code size.
When you come back to the code a year later, the short cut in those circumstances is clear and makes perfect sense immediately, but the setting of error flags or setting loop variables to the upper limit in order to exit the nested structures is not at all clear and is far more likely to lead to problems.
I'd re-iterate Dare2 from earlier:
Paul.
there are times when a short cut is the best method.
If you're embedded deep in loops and if..then..else..endif and case..endcase structures when it becomes clear there is no longer a point to being there, such as if an overflow occurs half way through a complex calculation, then it is easier to follow a shortcut than to follow the tortuous coding needed to exit every structure the "correct" way. It's also a lot more efficient and gives smaller code size.
When you come back to the code a year later, the short cut in those circumstances is clear and makes perfect sense immediately, but the setting of error flags or setting loop variables to the upper limit in order to exit the nested structures is not at all clear and is far more likely to lead to problems.
I'd re-iterate Dare2 from earlier:
GOTO and GOSUB are not bad code. It's how you use them that matters.IMO, bad code is code that is hard to support.
If it does the job adequately: If the next guy can understand it and enhance it: If you can maintain it 1 year down the track: Then it is good code.
That is all that really matters.
Paul.
I said real world examples. I've never seen a procedure have that many args in any app code i've seen and that code you've posted doesn't really show anything well..dioxin wrote:Kale,
look at the 2 examples posted above and show me how you would accomplish the same with easier to follow code.
Paul.
As for your argument about being 'embedded deep in loops' etc... if your inside nested loops more than 2 or 3 deep your doing something wrong already.
I admit Breaks and Continues are probably Goto's under the hood, but im talking about human readable code here and keeping it simple for them to understand. Gotos mess stuff up, period! If you design an app carefully from the beginning using a few simple rules then you will never need Goto and Gosub and you will probably wonder why you ever used them. bleh! :p
Kale,
you never go more than 3 structures deep? Surely you jest. I assumed you were a programmer! Even the basic Windows message loop for handling a key press is 4 structures deep before you even do anything!
But even really simple code that only needs 2 structures is easier to follow with the GOTO than with other exit stategies. Follow the above example and show me otherwise. How would you do it?
As for how real the examples were. The GOTO example is actually simplified in that post as it demonstrates the point well enough. In real life 6-8 structures deep is not that unusual.
I did exagerate the GOSUB example for effect but it is really based on a program I altered about 4 weeks ago.
There were 12 calls to the GOSUB and the parameters required were:
3 Integers
1 String
1 Integer Arrays with 1000 entries
1 User Defined array with 1000 entries, each entry being 7 strings
How long and how much code would it take to have to push that lot onto the stack for each procedure call? It took literally no time at all using GOSUB and is every bit as easy to follow as any other approach.
You still haven't shown how you would do the 2 examples posted. I accept there is little substance to them because they were intended to show the approach without hiding it in hunderds of lines of code but that should work to your advantage as your code to accomplish the same should be so crystal clear and succinct when not surrounded by the fluff of a real application that you will be able to demonstrate clearly the advantage of avoiding GOTO and GOSUB once and for all.
Paul.
you never go more than 3 structures deep? Surely you jest. I assumed you were a programmer! Even the basic Windows message loop for handling a key press is 4 structures deep before you even do anything!
But even really simple code that only needs 2 structures is easier to follow with the GOTO than with other exit stategies. Follow the above example and show me otherwise. How would you do it?
As for how real the examples were. The GOTO example is actually simplified in that post as it demonstrates the point well enough. In real life 6-8 structures deep is not that unusual.
I did exagerate the GOSUB example for effect but it is really based on a program I altered about 4 weeks ago.
There were 12 calls to the GOSUB and the parameters required were:
3 Integers
1 String
1 Integer Arrays with 1000 entries
1 User Defined array with 1000 entries, each entry being 7 strings
How long and how much code would it take to have to push that lot onto the stack for each procedure call? It took literally no time at all using GOSUB and is every bit as easy to follow as any other approach.
You're wrong.Gotos mess stuff up, period!
You still haven't shown how you would do the 2 examples posted. I accept there is little substance to them because they were intended to show the approach without hiding it in hunderds of lines of code but that should work to your advantage as your code to accomplish the same should be so crystal clear and succinct when not surrounded by the fluff of a real application that you will be able to demonstrate clearly the advantage of avoiding GOTO and GOSUB once and for all.
Paul.
Well, i'm convinced now that GOTO's and GOSUB's have their place but just not very often. Maybe an occaisional GOTO or GOSUB is not such a bad thing and then again maybe it is, i guess it depends on the circumstances and what your trying to achieve.
Anyway, its all fun until someone puts an eye out then its not so much fun anymore is it
Anyway, its all fun until someone puts an eye out then its not so much fun anymore is it

which looks prettier?
I like the procedure way more than the gosub way.
Code: Select all
Gosub TheLabel
TheLabel:
Debug "LOL"
Return
Code: Select all
Procedure DoIt()
Debug "LOL"
EndProcedure
DoIt()
Pupil,
I know I was never going to convince the folk who'd made their minds up about it but the argument has to be put so those who aren't yet stuck in their ways have the information to decide for themselves instead of just accepting one side of the argument as fact.
SFSxOI,
You're convinced they have their place when used wisely? Success!
Pheonix,
I'm not sure they are entirely the same.
GOSUB should have no overhead, it's just a CALL and RET at assembly level.
Procedures (I'm guessing 'cos I don't know) will almost certainly save registers and establish space on the stack when they're called even if they don't always need to. They then have to clear up afterwards before returning so there is probably a lot more overhead than with GOSUB.
josku_x
..looks pretty enough to me and it saves 30% of the typing compared to your PROCEDURE and is both faster and shorter when compiled.
Paul.
I know I was never going to convince the folk who'd made their minds up about it but the argument has to be put so those who aren't yet stuck in their ways have the information to decide for themselves instead of just accepting one side of the argument as fact.
SFSxOI,
You're convinced they have their place when used wisely? Success!
Pheonix,
I'm not sure they are entirely the same.
GOSUB should have no overhead, it's just a CALL and RET at assembly level.
Procedures (I'm guessing 'cos I don't know) will almost certainly save registers and establish space on the stack when they're called even if they don't always need to. They then have to clear up afterwards before returning so there is probably a lot more overhead than with GOSUB.
josku_x
Code: Select all
DoIt:
Debug "LOL"
RETURN
GOSUB DoIt
..looks pretty enough to me and it saves 30% of the typing compared to your PROCEDURE and is both faster and shorter when compiled.
Paul.
hehe. This whole thing is getting silly. Another hair to split:
lol. If we split this hair a few more times we'll be splitting the atom (and the Alliance of the Willing will invade us!)
Anyhow, here is something that may interest you (quickly contrived, gives procedure's a slight edge, however some better tests may prove otherwise).
Needs the extra typing to "goto" around the "DoIt" code, to a label.dioxin wrote:Code: Select all
DoIt: Debug "LOL" RETURN GOSUB DoIt
lol. If we split this hair a few more times we'll be splitting the atom (and the Alliance of the Willing will invade us!)

Anyhow, here is something that may interest you (quickly contrived, gives procedure's a slight edge, however some better tests may prove otherwise).
Code: Select all
Global aa.l, bb.l, cc.l ; Not needed for the gosubs
Goto jumpToAvoidTheGosubs ; Not needed for procs or if gosubs are last (after End)
abcG:
aa = bb + cc
Return
xyzG:
xx = yy + zz
Return
Procedure abcP()
aa = bb + cc
EndProcedure
Procedure xyzP(yy.l, zz.l)
ProcedureReturn yy + zz
EndProcedure
jumpToAvoidTheGosubs:
someLargeNumber = 1 ; must be very large!
w.s = "And the results (tah-dah)" + Chr(10) + Chr(10)
t = ElapsedMilliseconds()
For i=1 To someLargeNumber
bb = 1
cc = 1
abcP()
Next
t = ElapsedMilliseconds() - t
w+"abcP = " + Str(t) + " (" + Str(aa) + ")" + Chr(10)
t = ElapsedMilliseconds()
For i=1 To someLargeNumber
bb = 1
cc = 1
Gosub abcG
Next
t = ElapsedMilliseconds() - t
w+"abcG = " + Str(t) + " (" + Str(aa) + ")" + Chr(10)
t = ElapsedMilliseconds()
For i=1 To someLargeNumber
xx = xyzP(2,3)
Next
t = ElapsedMilliseconds() - t
w+"xyzP = " + Str(t) + " (" + Str(xx) + ")" + Chr(10)
t = ElapsedMilliseconds()
For i=1 To someLargeNumber
yy = 2
zz = 3
Gosub xyzG
Next
t = ElapsedMilliseconds() - t
w+"xyzG = " + Str(t) + " (" + Str(xx) + ")" + Chr(10)
MessageRequester("!",w,0)
End
@}--`--,-- A rose by any other name ..
Dare2,
well of course you'd put the GOSUBs beyond the END so as not to need the jump. I only did it the way I did so it was directly comparable to the "pretty" Procedure version and would hopefully take on some of the pretty characteristics of that version, at least in the eye of its creator.
The "less typing" comment wasn't meant to be taken too seriously, after all, if you call the GOSUB many times it takes 3 characters more typing each time than the PROCEDURE version so in real life it'll take more typing.. but don't tell the others or they'll use it to argue against GOSUBs!
As for the timing of GOSUB vs. PROCEDURE, I'm only able to speculate as I don't actually own PureBASIC so I can't compile or experiment with it but, as a guess, I'd say that the routines are both very short and in very tight loops so will be prone to the well known branch target alignment problem. If the code was moved around a bit, for example by swapping the position of the PROCEDURE and GOTO calling routines, or by adding a small amount of code at the start of the program, then it may give different results.
Sounds like atom spiltting again, I know, but you can gain or lose 20% in speed by altering the alignment of critical parts of your code.
Paul.
well of course you'd put the GOSUBs beyond the END so as not to need the jump. I only did it the way I did so it was directly comparable to the "pretty" Procedure version and would hopefully take on some of the pretty characteristics of that version, at least in the eye of its creator.
The "less typing" comment wasn't meant to be taken too seriously, after all, if you call the GOSUB many times it takes 3 characters more typing each time than the PROCEDURE version so in real life it'll take more typing.. but don't tell the others or they'll use it to argue against GOSUBs!
As for the timing of GOSUB vs. PROCEDURE, I'm only able to speculate as I don't actually own PureBASIC so I can't compile or experiment with it but, as a guess, I'd say that the routines are both very short and in very tight loops so will be prone to the well known branch target alignment problem. If the code was moved around a bit, for example by swapping the position of the PROCEDURE and GOTO calling routines, or by adding a small amount of code at the start of the program, then it may give different results.
Sounds like atom spiltting again, I know, but you can gain or lose 20% in speed by altering the alignment of critical parts of your code.
Paul.