-
May 12th, 2018, 06:05 PM
#1
Thread Starter
Hyperactive Member
GOSUB - Is It Realy That Bad?
I posted this earlier today in the VB6 section but for those of you who don't read those threads I htought I would repeat it here...
I like GOSUB. I started programming in Assembly and Turbo Pascal back when PC's first came out in the early ‘80s so I have been doing this for a long time.
There are two main advantages of using GOSUB: 1) no variables to push/pop from the stack and 2) any local variables don't need to initialized and destroyed on each call.
The supposed disadvantages of using GOSUB are: 1) it just isn't modern coding practice, 2) it leads to spaghetti code that is very hard to use and maintain, 3) it is only like a Sub and it can’t return a value like a Function and 4) because of (1) and (2) most younger programmers don’t even know when/how to use it and most “modern” programming languages don’t even include it.
Processors use gosub internally. They also use a lot of what is the equivalent of the GOTO command in VB/VBA but that is a discussion for another day.
I also find that GOSUB doesn’t make me write spaghetti code (at least any more than I do without using it). I can find a line label in my current procedure as fast as I can find a standalone routine and with proper commenting I dno’t hae any additional code maintenance issues.
I keep reading statements by other programmers about their disdain for GOSUB but their arguments are weak to non-existent for why we shouldn’t use it and why it made sense for Microsoft to remove it from VB.NET. I think that’s crazy so I decided I would test my assumptions regarding speed.
I worked up something approximating a real-world scenario and I wrote a simple program that call the repeating code via a Function and I wrote another routine that called the repeating code via a GOSUB command.
I got some very surprising results. Below are the time in milliseconds to execute the code 10,000 times.
|
Using Function |
Using GOSUB |
VBA |
1,092 |
475 |
Un-compiled VB6 |
960 |
472 |
Compiled VB6 |
371 |
866 |
Compiled VB6 (p-code) |
906 |
435 |
The code in VBA did about what I thought it would. This is basically like pseudo-code that can be “compiled” by VB6; it is not native machine code. The GOSUB code is 2.3 times faster.
Un-compiled VB6 is similar to VBA; the function calls are about 13% faster but the GOSUB code is only marginally faster than VBA although it is 2 times faster than the Function call code.
Using VB6 with code compiled to p-code was similar to un-compiled VB6 code but about 5-8% faster. I don’t use p-code for a variety of reasons but it is a bit faster than either VBA or un-compiled VB6. However, note that the GOSUB version is a bit more than 2 times faster like the other codings.
The surprise comes with code compiled to native machine code. BTW, the results were very similar when I optimized for small code or faster execution. As expected the use of the Function code was a bit over twice as fast. What was surprising was that the code using GOSUB was over 2.3 times as slow as the Function version and twice as slow as all of the other versions of the GOSUB coding for VBA, un-compiled VB6 and p-code VB6. Whoever did the compiler logic for GOSUB in VB6 did a horrible job!
So the bottom-line for me is that GOSUB is the way to go for VBA but programs using compiled VB6 to machine code will run faster with conventional Function or Sub calls.
I have the code and raw results available if anyone wants to play with them.
-
Dec 15th, 2023, 09:55 PM
#2
Member
Re: GOSUB - Is It Realy That Bad?
Hi,MountainMan
I have a classic basic code for my mechanical design, it contains many gosub lines. I dont want to translate it to VB6's sub function or sub routine. So would you show me an example how to use gosub in VB6? Thanks.
John
-
Dec 15th, 2023, 11:10 PM
#3
Re: GOSUB - Is It Realy That Bad?
Yeah GOSUB goes way back in time doesn't it? The execution speed doesn't surprise me... you can GOSUB to a label, which means you can't pass parameters. With a method you can, so there's some overhead in calling one as things have to be pushed to the stack first. With a gosub, it's just (or should be) a JMP to a specific memory address.
I'd be curious to see your testing code for this...The compiled VB6 numbers I find a bit surprising, especially considering the others.
-tg
-
Dec 16th, 2023, 06:36 AM
#4
Re: GOSUB - Is It Realy That Bad?
You forgot, you cannot define local scope and encapsulate variables using gosubs ...
https://github.com/yereverluvinunclebert
Skillset: VMS,DOS,Windows Sysadmin from 1985, fault-tolerance, VaxCluster, Alpha,Sparc. DCL,QB,VBDOS- VB6,.NET, PHP,NODE.JS, Graphic Design, Project Manager, CMS, Quad Electronics. classic cars & m'bikes. Artist in water & oils. Historian.
By the power invested in me, all the threads I start are battle free zones - no arguing about the benefits of VB6 over .NET here please. Happiness must reign.
-
Dec 16th, 2023, 02:58 PM
#5
Re: GOSUB - Is It Realy That Bad?
The compiled speed should put the final nail in the coffin. That plus the downsides, it's not worth it for a benefit in the IDE.
VBA has enough problems with unreadable and unmaintainable code. Half a second for 10,000 executions isn't worth it. If anything is that performance critical, it should have already been outsourced to a native DLL (which is a lot more practical now that tB can do it for x64 VBA in the same language).
There's also no comparison against an even better solution of redesigning to not need either GoSub or another function.
-
Dec 19th, 2023, 07:12 AM
#6
Member
Re: GOSUB - Is It Realy That Bad?
Hi MountainMan
Would be worth posting the code. Benchmarks without code aren't great because you can never tell if the implementor had an alterior motive, not saying you do
I must say I'm not a fan of GOSUB, mostly because you can't post parameters to the GOSUB block, and scope becomes hugely polluted. In a similar fashion, I'm also not a fan of having a tonne of global variables. I do enjoy seperating concerns.
One "interesting" feature of GOSUB though is that you don't lose scope. This means you can iterate over IEnumVariants in a different part of your code.
Code:
Public Function ForEach(Optional ByVal cb As stdICallable, Optional ByVal WithIndex as boolean = false) As stdEnumerator
Dim bLoopInitialised as boolean: bLoopInitialised = false
Dim ExitLoop as Boolean: ExitLoop = false
Dim v as variant, i as long: i=0
Do while true
'Increment index
i=i+1
'Obtain loop var from mode
select case mode
case EnumeratorType.FromCallable
if bLoopInitialised then
v = pCallback.run(v,i)
else
v = pCallback.Run(null,i)
bLoopInitialised=true
end if
if isNull(v) then ExitLoop = true
case EnumeratorType.FromIEnumVariant
if bLoopInitialised then
GoSub NextItem
else
GoSub InitIEnumVARIANT
bLoopInitialised = True
end if
case EnumeratorType.FromIEnumVariant
if bLoopInitialised then
if lb+i-1 <= ub then
v = vArr(lb+i-1)
else
ExitLoop = true
end if
else
Dim lb as long: lb = lbound(vArr,1)
Dim ub as long: ub = ubound(vArr,1)
if ub-lb+1 > 0 then
v = vArr(lb+i-1)
else
v = null
end if
end if
end select
if ExitLoop then Exit Do
if withIndex then
Call cb.Run(i,v)
else
Call cb.Run(v)
end if
Loop
set ForEach = me
Exit Function
'=========================================================================================================================
' IEnumVARIANT Iterator - Don't change the code below
'=================================
InitIEnumVARIANT:
For Each v In pEnumObject
Return
NextItem:
Next
ExitLoop = true
Return
End Function
Of course there are better ways to do this though. I wouldn't suggest anyone ever use code like this, as it really is confusing af...
I'm on a similar wavelength to fafalone here. Even though I use VBA regularly, VBA has enough problems with unreadable or unmaintainable code. Encouraging bad practice for such a minor performance gain, is it worth it?
-
Dec 19th, 2023, 07:53 AM
#7
Re: GOSUB - Is It Realy That Bad?
Originally Posted by MountainMan
So the bottom-line for me is that GOSUB is the way to go for VBA but programs using compiled VB6 to machine code will run faster with conventional Function or Sub calls.
I have the code and raw results available if anyone wants to play with them.
I am not sure how your conclusion was to use GOSUB from those benchmarks... GOSUB would result in a lot of global variables, harder to read (and therefore maintain) code, and the performance difference is about 500ms for 10,000 iterations (that is approx 0.05ms difference per call).
I am not convinced the performance boost for most situations would justify the code quality issues that would arise, under certain performance critical sections then it might possible be justified. Although if I wanted to write performance critical code I wouldn't be doing it in VBA anyway
-
Dec 19th, 2023, 10:19 AM
#8
Member
Re: GOSUB - Is It Realy That Bad?
Originally Posted by PlausiblyDamp
Although if I wanted to write performance critical code I wouldn't be doing it in VBA anyway
To be fair, it isn't always a choice.
-
Dec 20th, 2023, 04:38 AM
#9
Re: GOSUB - Is It Realy That Bad?
I used to code serious applications in DCL, a scripting language for VMS systems. I created demonstration RAD applications in pseudo code, converting to intermediate DCL to form working templates for eventual conversion to fortran, these programs would assist factory production at Mars chocolate, scheduled chocolate levels vs actual & c. Due to limitations of this language I had to use GOSUBs instead of sub routines/functions and I am telling you now how easy it is to remove/lose the matching return, it happens!. RETURNS are not physically paired to a GOSUB, any return you hit sends you back... not necessarily when you want it to. It is NOT a recommended method for really obvious control reasons regardless as to whether it is performant in speed.
https://github.com/yereverluvinunclebert
Skillset: VMS,DOS,Windows Sysadmin from 1985, fault-tolerance, VaxCluster, Alpha,Sparc. DCL,QB,VBDOS- VB6,.NET, PHP,NODE.JS, Graphic Design, Project Manager, CMS, Quad Electronics. classic cars & m'bikes. Artist in water & oils. Historian.
By the power invested in me, all the threads I start are battle free zones - no arguing about the benefits of VB6 over .NET here please. Happiness must reign.
-
Dec 21st, 2023, 05:55 AM
#10
Thread Starter
Hyperactive Member
Re: GOSUB - Is It Realy That Bad?
Originally Posted by PlausiblyDamp
I am not sure how your conclusion was to use GOSUB from those benchmarks... GOSUB would result in a lot of global variables,...
PlausiblyDamp,
A Gosub has to be in the same procedure as the calling code so it has access to all of the variables already in that procedure. So it doesn't cause any increase in Global variables. In fact, if you use say 10 parameters you had defined in the parent procedure, you would almost certainly have to pass them as parameters for a separate procedure call whereas in a Gosub they are already defined and likely have their values that don't need to be passed on the stack to a Gosub..
-
Dec 21st, 2023, 06:06 AM
#11
Thread Starter
Hyperactive Member
Re: GOSUB - Is It Realy That Bad?
Originally Posted by fafalone
The compiled speed should put the final nail in the coffin. That plus the downsides, it's not worth it for a benefit in the IDE.
VBA has enough problems with unreadable and unmaintainable code. Half a second for 10,000 executions isn't worth it. If anything is that performance critical, it should have already been outsourced to a native DLL (which is a lot more practical now that tB can do it for x64 VBA in the same language).
Strange, you use the performance times to say that Gosub has no advantage outside of the IDE but then say the difference in performance time means you shouldn't use Gosub. I am not sure you can have it both ways.
I disagree that VBA code is unreadable and unmaintainable. I've been doing VB/VBA for a long time and I don't find the VBA code to be worse than VB6. It does have the Win64 conditional compilation constant that makes things look goofy but this a) enabled us to use VBA in 64-bit Excel and b) TB is going to put us in the same situation on Windows 64-bit coding. Also, if TB ca n generate native DLL's when it is released doesn't exclude use of those DLL's in VBA.
-
Dec 21st, 2023, 06:09 AM
#12
Thread Starter
Hyperactive Member
Re: GOSUB - Is It Realy That Bad?
Originally Posted by yereverluvinuncleber
You forgot, you cannot define local scope and encapsulate variables using gosubs ...
I am not sure I understand your concern about local scope. Since Gosub's have to be embedded within a Procedure they have access to any procedure-level vari9abes and the global variables just like the code elsewhere calling the Gosub. In fact, if you Dim a variable in a Gosub that variable will go out of scope when the parent procedure goes out of scope.
-
Dec 21st, 2023, 06:17 AM
#13
Re: GOSUB - Is It Realy That Bad?
Originally Posted by MountainMan
PlausiblyDamp,
A Gosub has to be in the same procedure as the calling code so it has access to all of the variables already in that procedure. So it doesn't cause any increase in Global variables. In fact, if you use say 10 parameters you had defined in the parent procedure, you would almost certainly have to pass them as parameters for a separate procedure call whereas in a Gosub they are already defined and likely have their values that don't need to be passed on the stack to a Gosub..
Point taken, although if you have a procedure with a lot of variables declared and are using Gosub a lot then the procedure level variables are almost acting like global variables anyway. I am a big fan of simpler, smaller functions, locally declared variables, and functions with minimal side effects - Gosub pretty much goes against all of these things though.
-
Dec 21st, 2023, 06:18 AM
#14
Thread Starter
Hyperactive Member
Re: GOSUB - Is It Realy That Bad?
Originally Posted by techgnome
Yeah GOSUB goes way back in time doesn't it? The execution speed doesn't surprise me... you can GOSUB to a label, which means you can't pass parameters. With a method you can, so there's some overhead in calling one as things have to be pushed to the stack first. With a gosub, it's just (or should be) a JMP to a specific memory address.
I'd be curious to see your testing code for this...The compiled VB6 numbers I find a bit surprising, especially considering the others.
-tg
Techgnome, I will post code for VB6 and VBA (it is almost identical code) in the next day or so.
I disagree with not being able to pass variables. You just have to think about it a bit differently. It's true that the return address is the only thing put on the stack (so Return sends it back to the right place) but any variable you have in the calling procedure is available to the Gosub code. So if I have a variable "i" and I want to pass it to a Sub or a Function, I have to put it on the stack as a parameter in the call. With a Gosub, you have immediate access to "i". It is the same as passing a variable to a Proc "ByRef". If you want to have it be the equivalent of "ByVal" then you just use some other variable of the same type in your procedure (or you Di it in the Gosub; it only gets allocated once). That's basically how the VB compiler works anyway. When you do ByVal the compiler makes a copy of the variable on the stack, doing essentially exactly what I described.
-
Dec 21st, 2023, 06:20 AM
#15
Thread Starter
Hyperactive Member
Re: GOSUB - Is It Realy That Bad?
Originally Posted by JT870
Hi,MountainMan
I have a classic basic code for my mechanical design, it contains many gosub lines. I dont want to translate it to VB6's sub function or sub routine. So would you show me an example how to use gosub in VB6? Thanks.
John
John, it is incredibly easy to use. I am going to post my latest code in a day or so so you should be able to see how easy it is.
-
Dec 21st, 2023, 06:39 PM
#16
Thread Starter
Hyperactive Member
Re: GOSUB - Is It Realy That Bad?
[QUOTE=JT870 Hi,MountainMan
I have a classic basic code for my mechanical design, it contains many gosub lines. I dont want to translate it to VB6's sub function or sub routine. So would you show me an example how to use gosub in VB6? Thanks.[/QUOTE]
John,
Below is a very simple example of a Gosub in VB6/VBA. Note that what the subroutine does in this example is trivial and I would never write code using a Gosub like this but it should be simple and easy-to-understand.
Sub GosubExample()
Dim x As Long, y As Long, z As Long
x = 5
y = 6
GoSub MyGosubStart 'should put 11 in z
MsgBox z
Exit Sub
MyGosubStart:
z = x + y ' procedure-level variables x & y Dim'd and values set above in the procedure
Return
End Sub
-
Dec 21st, 2023, 10:56 PM
#17
Re: GOSUB - Is It Realy That Bad?
Yes, it can be bad. This is some code (very slightly modified) from the "Chaos and Fractals" book printed in the early 1990's. Pretty much all the code in each chapter has Gosub and Goto jumps that made it really hard to track down issues where the code I entered manually wasn't producing results identical to the book pictures.
Code:
' Filename: CANTORST.BAS
' Comments: This program draws the Cantor set staircase.
CLS
DIM xleft(10) AS DOUBLE
DIM yleft(10) AS DOUBLE
DIM xright(10) AS DOUBLE
DIM yright(10) AS DOUBLE
DIM r AS DOUBLE
DIM level AS INTEGER
DIM stair AS DOUBLE
DIM left AS INTEGER
DIM w AS INTEGER
INPUT "Part to remove (0 - 1): ", r
level = 7
stair = 1
left = 30
w = 420
xleft(level) = left
xright(level) = left + w
yleft(level) = left + .5 * (1 + stair) * w
yright(level) = left + .5 * (1 - stair) * w
SCREEN 12
' Compute dimension
IF r < 1 THEN d = LOG(2) / LOG(2 / (1 - r)) ELSE d = 0
PRINT "Dimension of Cantor set", d
GOSUB 100
END
' Draw line at lowest level of recursion
100 :
IF level > 1 GOTO 200
LINE (xleft(1), yleft(1))-(xright(1), yright(1))
GOTO 300
' Branch into lower levels
200 :
level = level - 1
' Left branch
xleft(level) = xleft(level + 1)
yleft(level) = yleft(level + 1)
xright(level) = .5 * ((1 - r) * xright(level + 1) + (1 + r) * xleft(level + 1))
yright(level) = .5 * (yright(level + 1) + yleft(level + 1))
GOSUB 100
' Right branch
xleft(level) = .5 * ((1 + r) * xright(level + 1) + (1 - r) * xleft(level + 1))
yleft(level) = .5 * (yright(level + 1) + yleft(level + 1))
IF stair THEN LINE (xleft(level), yleft(level))-(xright(level), yright(level))
xright(level) = xright(level + 1)
yright(level) = yright(level + 1)
GOSUB 100
level = level + 1
300 :
RETURN
-
Dec 22nd, 2023, 04:25 AM
#18
Re: GOSUB - Is It Realy That Bad?
Originally Posted by MountainMan
John,
Below is a very simple example of a Gosub in VB6/VBA. Note that what the subroutine does in this example is trivial and I would never write code using a Gosub like this but it should be simple and easy-to-understand.
Sub GosubExample()
Dim x As Long, y As Long, z As Long
x = 5
y = 6
GoSub MyGosubStart 'should put 11 in z
MsgBox z
Exit Sub
MyGosubStart:
z = x + y ' procedure-level variables x & y Dim'd and values set above in the procedure
Return
End Sub
One of the problems with that style of code is you have no idea what variables need to be set, or are modified, by the code after the Gosub without going and reading that code. With a function it would be obvious that you pass in two Longs and it returns a long. Also using a gosub means those three variables have very specific uses that isn't immediately obvious - if you gosub to that section then z will be overwritten.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|