Page 1 of 3 123 LastLast
Results 1 to 40 of 85

Thread: GOSUB - Is it really bad?

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2015
    Location
    Colorado USA
    Posts
    261

    GOSUB - Is it really bad?

    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,020 496
    Un-compiled VB6 894 496
    Compiled VB6 355 1063
    Compiled VB6 (p-code) 859 472

    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.05 times faster.

    Un-compiled VB6 is similar to VBA; the function calls are about 14% faster but the GOSUB code is the same as VBA although it is 80% 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 about 82% faster then the function call which is consistent with 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 3 times as slow as the Function version and more than 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 am not saying not to use Subs/Functions. I am saying tha tthere is a place for Gosub in the toolkit and that the compiled version in VB6 of this is lousy.

    I have the code and raw results available if anyone wants to play with them.
    Last edited by MountainMan; May 12th, 2018 at 11:09 PM. Reason: Bug fixes. re-run timings.

  2. #2
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by MountainMan View Post
    ...using compiled VB6 to machine code will run faster with conventional Function or Sub calls.
    If I remember correctly (from tests done years ago) - the slowdown-factor of GoSub
    (compared to calling dedicated SubRoutines) was even worse than your test-results.

    Quote Originally Posted by MountainMan View Post
    I have the code and raw results available if anyone wants to play with them.
    Yep, would like to take a look at the code which produced these results...

    Olaf

  3. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2015
    Location
    Colorado USA
    Posts
    261

    Re: GOSUB - Is it really bad?

    The VB6 files and Excel file (.xlsb) are attached...
    Attached Files Attached Files
    Last edited by MountainMan; May 12th, 2018 at 11:14 PM. Reason: Fixed bugs. Updated upload.

  4. #4
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: GOSUB - Is it really bad?

    need to remove the reference: vbAdvance Add-in 3.1

    the two subs are not equal.
    UseSubs have a calculation AFunction = dd / 4.123 while NoSubs dont have it.
    Need to be changed from
    Code:
    dd = (a + b) * c
    AFunction = dd / 4.123
    to
    Code:
    AFunction = (a + b) * c
    also in the AFunction you use ll = a + b - bb, but should be a = a + b - bb as you use that in NoSubs

    my timing:
    IDE: Sub1: 1135, Sub2: 774
    Native: Sub1: 2960, Sub2: 10863
    Pcode: Sub1: 1046, Sub2: 573

  5. #5
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by MountainMan View Post
    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.
    .
    You missed 5 which is Subs and Functions can be called from other routines and even placed in different modules so that you do not have to write the same code over and over and over again. This alone is reason enough to use them over the old Gosub.

    Of course I see a lot of people who abuse the use of these and using them where it would be better to just have inline code, even if it is repeated in multiple routines.

    Personally I haven't even thought about using a gosub for about 20 years now.

  6. #6
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: GOSUB - Is it really bad?

    There are a lot of things in VB6 that should be on your "do not use" list. Such a list not not absolute though, because these things do still have their place. They just shouldn't be near the top of your tool bag.


    At the very bottom of my bag I place fixed length String variables. Exception: they sometimes make sense in a UDT.

    But I have UDT arrays and I/O at the bottom of the bag, just above fixed Strings.

    Just above that comes DoEvents() calls.

    Then maybe On...GoSub and On...GoTo.

    Then comes GoSub/Return.

    Then maybe "Dim X As New Y" comes next.

    Above that comes GoTo, which is actually far more useful than any of the above.

    The main place it comes into play for me are things like using the GDI+ Flat API, where you often have to create instances of GDI+ objects layer by layer and then destroy them in reverse order of creation. If creation fails at some intermediate level of the creation stack a GoTo can be useful to jump to the appropriate point within the destruction code.

    Without GoTo you have to repeat a lot of the destruction calls.

    Of course that would all go away if we ever got a proper GDI+ ActiveX API (ActiveX is not the same as COM but a superset of it).


    Everyone has his own list. We only get into trouble when we let it become a set of religious commandments. Some people crave commandments though, probably in an attempt to simplify programming instead of trying to learn the entire language.

  7. #7

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2015
    Location
    Colorado USA
    Posts
    261

    Re: GOSUB - Is it really bad?

    DataMiser - I am not arguing for Gosub instead of traditional Subs and Functions but rather the possibility of having Gosub in addition to them. The only place I think of even potentially using Gosub's is when I have repeating code within a Sub or a Function and I don't need to call it from any other procedure.

    Dilettante - Goto's are worthwhile in a number of situations. I find them especially useful in procedure exits. Almost all of the time I want to have every exit from a procedure happen at the same point and executing the same exit code. In many complicated procedures you have to really contort the code to avoid the Goto and I find it easier not to do those contortions which often unnecessarily complicate the code and slow down execution.

  8. #8
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    Hmm, I suppose I'll weigh in on this one. Personally, I think there's a time and place for all the stuff listed here. The only thing I can think of that I'd never do is to declare a variable and let it default to the Variant type. If I want a Variant, I'll say so. Beyond that, I occasionally use everything.

    However (and that's a big however), for a noob, we may want to recommend against certain things, just so they don't think they're acceptable in just any situation. Goto, DoEvents, and probably Gosub come to mind. But once we understand appropriate places for them, I say that it should all be on the table. Let me go through my ideas on the various statements mentioned.

    GoTo. Truth be told, I only use this in one specific situation, and cringe anytime else I see it used. Let's say I've got a procedure that does several initialization things, like maybe opening a couple of ANSI files and maybe opening a few different database tables. And let's further say that, as we drop through this procedures, there may be several conditions that would cause this procedure to prematurely exit (possibly user canceling or certain criteria not met). It's here that a GoTo makes perfect sense to jump down to the bottom and close everything up. Without that GoTo, we'd have to put our close-up code in every place where we might exit (or possibly build unwieldy If statements that have our indentation taking our code off the screen.

    DoEvents. I also agree that this is one we should typically stay far away from. However, again, there's one place where it's absolutely essential. If we're in some long-running loop (doing whatever), and we'd like to give the user the opportunity to cancel, a DoEvents is the only way to get this done. If you want an excellent example of this, take a look at the code under the "Play" button of my recent DX9 project, seen here. And just to say it, DoEvents is not the solution to getting various screen objects to refresh. We should find the appropriate .Refresh method or possibly make an Invalidate API call.

    Dim obj As New cClass. This is also one I use with care. We must have a thorough understanding of how COM objects work before using this one. We should recognize that we're implicitly using it anytime we use our form names as object variables (as many of us frequently do) or when we set the VB_PredeclaredId to true on a class object. However, when I have a class that I need to use for a moment, and then destroy it, I see no reason not to use the Dim obj As New cClass syntax. I use it in short procedures and I occasionally use it in forms that quickly collect a bit of information. Here's an example of using it in a short procedure:
    Code:
    
    Private Sub CalcGdiAndKsdiAndWrite(GcdFileInfo As GcdFileSideType, GcdFleNum As Long, SideWord2 As String)
        Dim oGdiKsdi As New clsParamsIdxCalc ' It will self-destroy.
        '
        ' Do calculation.
        CalcGdiAndKsdi GcdFileInfo, oGdiKsdi
        '
        ' Write GDI into GCD file.
        Print #GcdFleNum, SideWord2 & "GDI":                Print #GcdFleNum, Format$(oGdiKsdi.Answers(TheGdi), "0.0###########")
        '
        ' Write KSDI into GCD file.
        Print #GcdFleNum, SideWord2 & "KSDI":               Print #GcdFleNum, Format$(oGdiKsdi.Answers(TheKsdi), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiPelvicAntPst":   Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw1), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiPelvicUpDn":     Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw2), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiPelvicIntExt":   Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw3), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiHipFlxExt":      Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw4), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiHipAddAbd":      Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw5), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiHipIntExt":      Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw6), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiKneeFlxExt":     Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw7), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiAnkleDorPla":    Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw8), "0.0###########")
        Print #GcdFleNum, SideWord2 & "KsdiFootIntExt":     Print #GcdFleNum, Format$(oGdiKsdi.Answers(KsdiRaw9), "0.0###########")
    End Sub
    
    Gosub. I've never understood all the fuss about Gosub. As far as I know, it's worked the same as it has since early versions of BASIC. It just shares all the variables with whatever procedure you're in (which is quite different from a Sub or Function call). When writing code, I must admit that I always think in terms of a Sub or Function (or maybe Property) before thinking of a Gosub, but a Gosub is certainly on the list in those cases where I repeatedly need to do some little thing. In fact, I'll sometimes use a Gosub just to get long initialization stuff off of the top of some procedure. Let me find some examples where I've used it:

    Code:
    
    
    Friend Sub PlotCopPath(CopBal As CopBalanceInfoType, pic As PictureBox)
        ' Before this is called, CopBal must be all calculated.
        Dim k As Long
        Dim deltaX As Double
        Dim deltaY As Double
        Const dBorder As Double = 0.1
        Dim offsetX As Double
        Dim offsetY As Double
        Dim mm As Double
        Dim m As Double
        Dim pi As Double
        Dim r As Double
        Dim x1 As Single
        Dim x2 As Single
        Dim y1 As Single
        Dim y2 As Single
        '
        ' Frame it.
        pic.ScaleMode = vbPixels
        '
        x1 = 0
        y1 = 0
        x2 = pic.ScaleLeft + pic.ScaleWidth - 1
        y2 = 0
        PlotPicLine pic, x1, y1, x2, y2, 0&
        '
        x1 = pic.ScaleLeft + pic.ScaleWidth - 1
        y1 = 0
        x2 = pic.ScaleLeft + pic.ScaleWidth - 1
        y2 = pic.ScaleTop + pic.ScaleHeight - 1
        PlotPicLine pic, x1, y1, x2, y2, 0&
        '
        x1 = 0
        y1 = pic.ScaleTop + pic.ScaleHeight - 1
        x2 = pic.ScaleLeft + pic.ScaleWidth - 1
        y2 = pic.ScaleTop + pic.ScaleHeight - 1
        PlotPicLine pic, x1, y1, x2, y2, 0&
        '
        x1 = 0
        y1 = 0
        x2 = 0
        y2 = pic.ScaleTop + pic.ScaleHeight - 1
        PlotPicLine pic, x1, y1, x2, y2, 0&
        '
        ' Origin of pic is naturally top-left.  We want it to be bottom left.
        ' Also, we treat it as square (not rectangular) so we must scale X the same as Y (or the path will be distorted).
        ' If not worrying about X being scaled the same as Y, we can go:
        '
        '       pic.Scale (MinX - dBorder, MaxY + dBorder)-(MaxX + dBorder, MinY - dBorder)
        '
        deltaX = CopBal.MaxX - CopBal.MinX
        deltaY = CopBal.MaxY - CopBal.MinY
        If deltaY > deltaX Then
            m = deltaY
            offsetX = (deltaY - deltaX) / 2
        Else
            m = deltaX
            offsetY = (deltaX - deltaY) / 2
        End If
        mm = Abs((CopBal.MinX - dBorder) - (CopBal.MinX + m + dBorder))
        'mm = Abs((CopBal.MinY + m + dBorder) - (CopBal.MinY - dBorder)) ' It's the same for both.
        '
        ' Show legend numbers.
        pic.ScaleMode = vbInches
        pic.CurrentX = 0.02
        pic.CurrentY = 3.94
        pic.Print "0"
        '
        pic.CurrentX = 0.02
        pic.CurrentY = 0
        pic.Print Format$(mm, "#0"); "mm"
        '
        pic.CurrentX = 3.84 - Len(Format$(mm, "#0")) * 0.12
        pic.CurrentY = 3.94
        pic.Print Format$(mm, "#0"); "mm"
        '
        x1 = CopBal.MinX - dBorder - offsetX
        y1 = CopBal.MinY + m + dBorder - offsetY
        x2 = CopBal.MinX + m + dBorder - offsetX
        y2 = CopBal.MinY - dBorder - offsetY
        SetPicScale pic, x1, y1, x2, y2
        '
        For k = 2 To CopBal.CalcFrameCount
            x1 = CopBal.CalcFramesCop.X(k - 1)
            y1 = CopBal.CalcFramesCop.Y(k - 1)
            x2 = CopBal.CalcFramesCop.X(k)
            y2 = CopBal.CalcFramesCop.Y(k)
            PlotPicLine pic, x1, y1, x2, y2, &H800000
        Next k
        '
        If Not mbSuppressBalCircleAndOval Then
            '
            ' And now the circle.
            pi = Atn(1) * 4
            r = Sqr(CopBal.CircleArea95 * 100 / pi)
            PlotPicCircle pic, CSng(r), &H6060FF
            '
            ' And now the ellipse.
            ' 1 = x^2 / a^2 + y^2 / b^2     ' Fundamental equation of an ellipse.
            ' y = +- sqr(1 - x^2/a^2) * b   ' Given x, a, & b, solve for y.
            Dim dStep As Double
            Dim dIdx As Double
            Dim SemiMajorSq As Double
            Dim dIdxStart As Double
            Dim dIdxEnd As Double
            Dim dAngle As Double
            Dim dSinAngle As Double
            Dim dCosAngle As Double
            '
            SemiMajorSq = CopBal.SemiMajorA * CopBal.SemiMajorA
            ' We're oriented up and down, so we've got to rotate by 90 in addition to the angle.
            ' Also CopBal.EllipseAngle is in degrees.
            dAngle = (pi / 2) - CopBal.EllipseAngle * pi / 180
            dSinAngle = Sin(dAngle)
            dCosAngle = Cos(dAngle)
            '
            dIdxStart = 0
            dIdxEnd = CopBal.SemiMajorA * 15 / 16
            dStep = CopBal.SemiMajorA / 200 ' Axes are always positive.
            For dIdx = dIdxStart To dIdxEnd Step dStep
                GoSub CalcXYAndPlotEllipse
            Next dIdx
            dIdxStart = dIdxEnd
            dIdxEnd = CopBal.SemiMajorA * 63 / 64
            dStep = CopBal.SemiMajorA / 400 ' Axes are always positive.
            For dIdx = dIdxStart To dIdxEnd Step dStep
                GoSub CalcXYAndPlotEllipse
            Next dIdx
            dIdxStart = dIdxEnd
            dIdxEnd = CopBal.SemiMajorA * 1023 / 1024
            dStep = CopBal.SemiMajorA / 800 ' Axes are always positive.
            For dIdx = dIdxStart To dIdxEnd Step dStep
                GoSub CalcXYAndPlotEllipse
            Next dIdx
            dIdxStart = dIdxEnd
            dIdxEnd = CopBal.SemiMajorA
            dStep = CopBal.SemiMajorA / 1600 ' Axes are always positive.
            For dIdx = dIdxStart To dIdxEnd Step dStep
                GoSub CalcXYAndPlotEllipse
            Next dIdx
            '
        End If
        '
        Exit Sub
        '
    CalcXYAndPlotEllipse:
        '
        ' Each of these (or both) can be turned negative to give the ellipse perimeter in each of the four quadrants.
        x1 = dIdx
        y1 = Sqr(1 - (x1 * x1) / SemiMajorSq) * CopBal.SemiMinorB
        '
        x2 = x1 * dCosAngle - y1 * dSinAngle
        y2 = x1 * dSinAngle + y1 * dCosAngle
        PlotPicEllipse4Pts pic, x2, y2, &H60D060
        x2 = -x1 * dCosAngle - y1 * dSinAngle
        y2 = -x1 * dSinAngle + y1 * dCosAngle
        PlotPicEllipse4Pts pic, x2, y2, &H60D060
        x2 = x1 * dCosAngle + y1 * dSinAngle
        y2 = x1 * dSinAngle - y1 * dCosAngle
        PlotPicEllipse4Pts pic, x2, y2, &H60D060
        x2 = -x1 * dCosAngle + y1 * dSinAngle
        y2 = -x1 * dSinAngle - y1 * dCosAngle
        PlotPicEllipse4Pts pic, x2, y2, &H60D060
        '
        Return
    End Sub
    
    ... or ...

    Code:
    
    Private Sub C3dAlreadyUsed(txt1 As TextBox)
        Dim i As Long
        Dim b As Boolean
        Dim txt2 As TextBox
        '
        If txt1.Text = vbNullString Then Exit Sub
        '
        Set txt2 = txtC3dStatic: GoSub DoCheck: If b Then Exit Sub
        For i = 1 To 3
            Set txt2 = txtC3dFlexFloor(i):      GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dFlexBox(i):        GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dExtFloor(i):       GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dExtDevice(i):      GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dRotLeft(i):        GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dRotRight(i):       GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dLatBndLeft(i):     GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dLatBndRight(i):    GoSub DoCheck: If b Then Exit Sub
        Next i
        Exit Sub
        '
    DoCheck:
        If txt1 Is txt2 Then Return         ' Don't match ourselves
        If txt1.Text = txt2.Text Then
            b = True
            txt1.Text = vbNullString
            MsgBox "This C3D is already used.  You can not use the same C3D in two different spine motion locations.  You must clear it from where it is used to use it in this location.", vbCritical, App.Title
        End If
        Return
    End Sub
    
    I think the last thing Dil said should be taken to heart.

    Quote Originally Posted by dilettante View Post
    We only get into trouble when we let it become a set of religious commandments. Some people crave commandments though, probably in an attempt to simplify programming instead of trying to learn the entire language.
    Sure, when we're learning, some things just seem very tempting (such as GoTo and DoEvents), and we should stay away from them. However, there's an appropriate time and place for about everything.

    All The Best,
    Elroy
    Last edited by Elroy; May 13th, 2018 at 06:41 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  9. #9
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: GOSUB - Is it really bad?

    I agree with Elroy.

    as for me, DoEvents is essential. in my "infinite-game-loop" where the only way to exit is a public boolean condition (when user chooses to exit).
    without the DoEvents there will be problems. but as Im also aware the we should not use DoEvents like crazy I use it together with one API:
    Code:
    If GetQueueStatus(QS_ALL) Then DoEvents
    I don't use GoTo that much, but sometimes i like to use it, not because I need it, but because It looks better. example:
    Code:
    Private Sub MissionKillCheck()
        Dim l&
        
        With NP(z)
            For l = 0 To 7
                If .PayReq(l).Type = 4 Then GoTo Killquest
            Next l
        End With
        Exit Sub
    Killquest:
        l = 0
        Do
            If Gm.KillList(l) = -1 Then Exit Do Else l = l + 1
        Loop Until l > UBound(Gm.KillList)
        If l > UBound(Gm.KillList) Then ReDim Preserve Gm.KillList(l)
        Gm.KillList(l) = z
    End Sub
    I use fixed Strings, not often but sometimes.
    one example is when I need a 1-length character, that i use at the end of the "text" to create a blinking effect (using textout)
    another is when theres options (like a listbox) where the user has different options, i use a fixed length string for those.

    as for GoSub I have never used it.

  10. #10
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    Fixed length strings are very strange animals. They absolutely have uses in UDTs. And I do occasionally use them for other purposes.

    However, they behave very differently than many people realize. For one, the compiler resolves them down much more than variable length strings. For instance, you can't pass them as arguments. You may think that you are, but you're not. Anytime a fixed length string is used as an argument, it's converted to a BSTR (i.e., variable length string) before it's passed. If it's changed by the called procedure, some strange logic is executed upon return to make sure the original fixed length string isn't over-run.

    And, you can't even get their memory address (unless they're in a UDT and you just use an offset from where they are in that UDT). VarPtr() will take a fixed lengh string. However, as previously stated, a BSTR is created, and that's what's passed to VarPtr(), and that's the address that is returned (i.e., an address to a temporary BSTR variable).

    Therefore, we're hardly gaining anything when we use stand-alone (non-UDT) fixed length strings, especially if we'll be using them as arguments. In fact, they may substantially slow things down, because of all the temporary BSTR creation.

    Here's some code that illustrates the weirdness of them:
    Code:
    
    Option Explicit
    
    Private Sub Form_Click()
        Dim s As String * 4
        '
        s = "asdf"
        Debug.Print s   ' "asdf" is printed.
        Call test(s)
        Debug.Print s   ' "1234" is printed.
    End Sub
    
    Private Sub test(s As String)
        s = "123456789"
        Debug.Print s   ' The full "123456789" string is printed.
    End Sub
    
    
    Best Regards,
    Elroy

    EDIT1: Also, I don't have an easy way to prove it, but I'd bet that BSTRs are created anytime we're doing string concatenation. For example ...
    Code:
    
    Option Explicit
    
    Private Sub Form_Click()
        Dim s1 As String * 4
        Dim s2 As String * 4
        Dim s3 As String * 8
        '
        s1 = "asdf"
        s2 = "qwer"
    
        s3 = s1 & s2
    
    End Sub
    
    ... in that last line (where s3 is assigned), the following is happening:
    1. Convert s1 to a temporary BSTR.
    2. Convert s2 to a temporary BSTR.
    3. Create a temporary BSTR that is the concatenation.
    4. Assign to s3, making sure we didn't over-run.

    Someone should do a speed-test of fixed length strings verses BSTRs doing that.
    Last edited by Elroy; May 13th, 2018 at 10:26 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  11. #11
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,989

    Re: GOSUB - Is it really bad?

    If you are writing for yourself, you can do whatever you want. If the only person who will ever maintain your code is you, then write in whatever fashion is easiest for you to maintain. If others will see/maintain the code, then you have other factors to consider.
    My usual boring signature: Nothing

  12. #12
    Lively Member
    Join Date
    Jun 2016
    Posts
    109

    Re: GOSUB - Is it really bad?

    ... I have to confess, i´m using GOTO quite often. Mostly in the context of parsing strings:

    Code:
    nxt:
        pos = InStr(pos + 1, somestring, searchstring)
        If pos Then
            ´do something with substring
            goto nxt
        end if
        ........
    I know, you could put this into a Do ... Loop.
    But this comes with a cost, performancewise, and I don´t think it will be even more readable.

    As for GOSUB, there are certain things you just cannot do without it.
    It is kind of Inheritance for the poor

  13. #13
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    Hi tubus,

    I apologize if I'm insulting, but, to my eyes, that's almost the definition of spaghetti code. When you, or someone else, comes back around and wants to enhance it, and maybe add a second GoTo, jumping back up to some other spot, then things just start getting out of hand.

    Even if there is a performance hit, I'd put that in a loop, possibly checking some Boolean flag as to when to get out.

    Best Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  14. #14
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: GOSUB - Is it really bad?

    to use goto instead of a loop is actually bad code. we do have a replacement for old basic methods and its do/loop while/wend.
    now, we can use goto of course, but why? it will not speed up and it will not make the code more readable. when a programmer read "do/loop" he will know immediately its a loop.
    i can understand when we use goto to "go ahead" a function, instead of adding "if's". or if we want to escape a for/next instead of adding a if/endif.

    as for GoSub, we do have sub/functions for that purpose. i can't see any use except if we want to have everything within 1 function, but it will not make it more readable and the GoSub can only be called within the function, so its limited, and performance wise, its slower in native code.

  15. #15

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2015
    Location
    Colorado USA
    Posts
    261

    Re: GOSUB - Is it really bad?

    You can easily escape a for/next without a goto by using "Exit For"...

  16. #16
    Lively Member
    Join Date
    Jun 2016
    Posts
    109

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by Elroy View Post
    Hi tubus,
    I apologize if I'm insulting, but, to my eyes, that's almost the definition of spaghetti code. When you, or someone else, comes back around and wants to enhance it, and maybe add a second GoTo, jumping back up to some other spot, then things just start getting out of hand.

    Even if there is a performance hit, I'd put that in a loop, possibly checking some Boolean flag as to when to get out.
    ... I know. May be its because I started my programming career with assembly-programming, so it looks just kind of natural to me

    But say: how would you do it?

    Whenever I think of it, either you have to do the Instr twice, or introduce auxillary variables.

    You just cannot make it simpler that a plain GOTO.

    (And this is in the inner loops of my program, and performance counts)

  17. #17
    Lively Member
    Join Date
    Jun 2016
    Posts
    109

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by baka View Post
    .... i can't see any use except if we want to have everything within 1 function, but it will not make it more readable and the GoSub can only be called within the function, so its limited, and performance wise, its slower in native code.
    ... well sometimes you just have to have everything within 1 function, and so GOSUB is the only way, due to lack of true Inheritance in VB6.

  18. #18
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    Hi tubus,

    Without seeing more of what you'd be doing, it's a bit hard to say exactly how I'd do it. However, with what you've provided, this is how I'd be thinking:

    Code:
    
        Dim bKeepLooping As Boolean
        Do
            bKeepLooping = False
            pos = InStr(pos + 1, somestring, searchstring)
            If pos Then
                ' do something with substring
                bKeepLooping = True
            End If
            If Not bKeepLooping Then Exit Do
        Loop
    
    
    I'd just always be looking at how to make some kind of loop out of it.

    Best Regards,
    Elroy

    EDIT1: Or, I could have put a Loop While bKeepLooping at the bottom, but I have a bad habit of just putting an If test in my loops rather than letting the loop test.

    EDIT2: After staring at your example some more, here's yet a more terse way to do it:

    Code:
    
        Do
            pos = InStr(pos + 1, somestring, searchstring)
            If pos = 0 Then Exit Do
            ' do something with substring
        Loop
    
    
    Last edited by Elroy; May 13th, 2018 at 12:44 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  19. #19
    PowerPoster
    Join Date
    Aug 2010
    Location
    Canada
    Posts
    2,412

    Re: GOSUB - Is it really bad?

    This should work without the extra variable:

    Code:
    Do
       pos = InStr(pos + 1, somestring, searchstring)
       
       If pos Then
          ' Do Something
       End If
    Loop While pos
    Although you'll want to watch out for the special cases where searchstring = "" (returns start, not 0) and for cases where somestring and/or searchstring is vbNullString. You can get yourself into an infinite loop.
    Last edited by jpbro; May 13th, 2018 at 12:48 PM.

  20. #20
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    @jpbro: I think we posted at the same time (me, with my EDIT2).

    EDIT1: Actually, I think mine might be a bit faster, in that it only tests pos once.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  21. #21
    PowerPoster
    Join Date
    Aug 2010
    Location
    Canada
    Posts
    2,412

    Re: GOSUB - Is it really bad?

    I guess we did! Notice I just added a little caveat at the end of my post re: infinite lops (though the original code with Goto would need the same checks).

  22. #22
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by MountainMan View Post
    You can easily escape a for/next without a goto by using "Exit For"...
    yes, of course, as Exit Do, Exit Sub etc.

    lets say:
    Code:
    For i=0 to 5: if then: Next i
    this will look into an array and if "found" then=
    we can do it in many ways ,lets see:

    - Call a Function + Exit For/Exit Sub
    - If/endIf + Exit For/Exit sub
    - GoSub + Exit For/Exit sub
    - GoTo
    - Found=True + Exit For

    now, if the function is "big" Call a Function could make it more readable. we don't like to have too much in 1 function, it makes it hard to manage later on.
    If/EndIf could do, depends on how much content. This is quite common use.
    GoSub is not to prefer here, but could be used if we allow "multiple" found (but I prefer a Function instead)
    GoTo, this one does two things for us, Exit For and also "Jump ahead".
    Found=True + Exit for: To let know we found something we need a variable (will explain)

    - GoTo or Found=True
    when we use Exit For at the end of i or let the For run until end "i" will be 5 in both cases.
    we can not use as condition, instead we need to add a variable like Found=True or a=i.
    here we can use GoTo to skip the condition, we can also use a found "i", the only thing we need is a End Sub after the For/Next.
    that is why exit for is not the same as goto in this case.

  23. #23
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by tubus View Post
    ... well sometimes you just have to have everything within 1 function, and so GOSUB is the only way, due to lack of true Inheritance in VB6.
    give example. in my 20 years programming i have never used it. what can not be done without GoSub?

  24. #24
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    @tubus: You know? I should come clean. I've been programming for quite a few decades now. When I first started, I inherited some wicked accounting code. My undergraduate degree is actually in Accounting, so the functional objectives of the program were very clear to me. And this code I inherited actually accomplished those objectives fairly well.

    However, it was full of GoTo's, and many of my earlier coding projects built upon those examples and practices. When VB came along, and, at about the same time, I was able to "escape" that project, I was well aware of the ... ummm ... badness of using GoTo's. It was not easy, but I forced myself to abandon all use of them. For many years, I refused to use them for any purpose what-so-ever!

    And, it is a different way of thinking. For a while, I'd stare at something like you presented, and think "now how do I do that without a Goto?" However, in not too long, it became second-nature to me. And now, it'd just never dawn on me to use a GoTo.

    And also, under very specific circumstances (basically just the one outlined in post #8 above), I do allow myself the occasional indulgence of a GoTo.

    I just thought I'd share that with you.

    Take Care,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  25. #25
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by baka View Post
    what can not be done without GoSub?
    *laughs* Baka, I just couldn't resist.

    Actually, I use a Gosub when I've got something that I know won't be used except in one specific procedure. One of the examples I gave in post #8 (shown again below) illustrates that well.

    Code:
    
    Private Sub C3dAlreadyUsed(txt1 As TextBox)
        Dim i As Long
        Dim b As Boolean
        Dim txt2 As TextBox
        '
        If txt1.Text = vbNullString Then Exit Sub
        '
        Set txt2 = txtC3dStatic: GoSub DoCheck: If b Then Exit Sub
        For i = 1 To 3
            Set txt2 = txtC3dFlexFloor(i):      GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dFlexBox(i):        GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dExtFloor(i):       GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dExtDevice(i):      GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dRotLeft(i):        GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dRotRight(i):       GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dLatBndLeft(i):     GoSub DoCheck: If b Then Exit Sub
            Set txt2 = txtC3dLatBndRight(i):    GoSub DoCheck: If b Then Exit Sub
        Next i
        Exit Sub
        '
    DoCheck:
        If txt1 Is txt2 Then Return         ' Don't match ourselves
        If txt1.Text = txt2.Text Then
            b = True
            txt1.Text = vbNullString
            MsgBox "This C3D is already used.  You can not use the same C3D in two different spine motion locations.  You must clear it from where it is used to use it in this location.", vbCritical, App.Title
        End If
        Return
    End Sub
    
    I must admit that my code is not sprinkled throughout with Gosub's. But I do keep them in my bag of tricks.

    But, to take up your challenge, we can combine two concepts presented in this thread and find something a Gosub can do that a Procedure can't. And that's the "true" manipulation of a fixed-length-string. As stated, when passed, a fixed-length-string is converted to a BSTR. However, if used in a Gosub's code, you'd still have direct access to the fixed-length-string.

    I must also admit that I don't think I've ever taken advantage of that fact though.

    Take Care,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  26. #26
    Lively Member
    Join Date
    Jun 2016
    Posts
    109

    Re: GOSUB - Is it really bad?

    Hi Elroy & jbro
    Quote Originally Posted by Elroy View Post
    Code:
    
        Do
            pos = InStr(pos + 1, somestring, searchstring)
            If pos = 0 Then Exit Do
            ' do something with substring
        Loop
    
    ..hey thanks, thats probably the way do do it!

    May still have somewhat of a performance hit, but certainly not to bad. I will consider this from now on.

    Regarding GOSUB: if in a somewhat *complex* SUB/FUNCTION you use a SUB (which needs *many* of its local variables) instead of a GOSUB what do you do?
    Pass dozens of variables to the SUB? (not so good!). Or make all this variables GLOBAL? ( also not so good!)
    Last edited by tubus; May 13th, 2018 at 01:45 PM.

  27. #27
    PowerPoster PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Pontypool, Wales
    Posts
    2,458

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by tubus View Post
    Hi Elroy & jbro


    ..hey thanks, thats probably the way do do it!

    May still have somewhat of a performance hit, but certainly not to bad. I will consider this from now on.

    Regarding GOSUB: if in a somewhat *complex* SUB/FUNCTION you use a SUB (which needs *many* of its local variables) instead of a GOSUB what do you do?
    Pass dozens of variables to the SUB? (not so good!). Or make all this variables GLOBAL? ( also not so good!)
    You could wrap the various variables into a class (or structure) and pass that to the routine as a single parameter. Depending on the actual situation the variables might be better as class level variables and the various subs and functions are acting on these class level variables.

  28. #28
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: GOSUB - Is it really bad?

    well I would not use GoSub, instead:
    Code:
    Private Function DoCheck(txt1 As TextBox, txt2 As TextBox) As Boolean
        If txt1 Is txt2 Then Exit Function
        If txt1.Text = txt2.Text Then
            txt1.Text = vbNullString
            MsgBox "This C3D is already used.  You can not use the same C3D in two different spine motion locations.  You must clear it from where it is used to use it in this location.", vbCritical, App.Title
            DoCheck = True
        End If
    End Function
    
    Private Sub C3dAlreadyUsed(txt1 As TextBox)
        Dim i As Long
        If txt1.Text = vbNullString Then Exit Sub
    
        If DoCheck(txt1, txtC3dStatic) Then Exit Sub
        For i = 1 To 1
            If DoCheck(txt1, txtC3dFlexFloor) Then Exit Sub
            If DoCheck(txt1, txtC3dFlexBox) Then Exit Sub
        Next i
    End Sub
    so no we can do without GoSub.

  29. #29
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by baka View Post
    well I would not use GoSub, instead:
    Code:
    Private Function DoCheck(txt1 As TextBox, txt2 As TextBox) As Boolean
        If txt1 Is txt2 Then Exit Function
        If txt1.Text = txt2.Text Then
            txt1.Text = vbNullString
            MsgBox "This C3D is already used.  You can not use the same C3D in two different spine motion locations.  You must clear it from where it is used to use it in this location.", vbCritical, App.Title
            DoCheck = True
        End If
    End Function
    
    Private Sub C3dAlreadyUsed(txt1 As TextBox)
        Dim i As Long
        If txt1.Text = vbNullString Then Exit Sub
    
        If DoCheck(txt1, txtC3dStatic) Then Exit Sub
        For i = 1 To 1
            If DoCheck(txt1, txtC3dFlexFloor) Then Exit Sub
            If DoCheck(txt1, txtC3dFlexBox) Then Exit Sub
        Next i
    End Sub
    so no we can do without GoSub.
    Hi baka,

    Yeah, I knew I could do that one with procedures. I was just saying that a Gosub felt correct to me in that situation. The fixed-length-string example is the only thing I can think of where a Gosub can actually do something that a procedure can't. I also "get" tubus's point though about a "poor man's inheritance". We just stay "in-scope" with everything that's going on, rather than having to determine the argument list.

    IDK, I suppose it's another case of "to each their own". Personally, I think we should shy away from GoTo's except in extremely specific circumstances; however, I see little reason to not occasionally use Gosub when it feels right.

    All The Best,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  30. #30
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: GOSUB - Is it really bad?

    I agree. it is there so why not use it if we feel its right or look ok or whatever.
    I try to stay away from it, this because it is easy to start using it too much, like a habit, thinking; hmm. can i use it now?

    About the Fixed String issue, I only use it for specific needs and usually temporary or within a function.
    To pass it, usually the Fixed String is in a UDT already.

    But lets say I want to call a function to "do something" with the string.
    usually we use a sub/function because we need the string to change into something.
    the byref will create a string, we do whatever and return into the fixed string,
    here, even if the string is out of boundary it will not create an error, we are safe.
    if we instead want to send it to another fixed string, im sure we would use UDT.
    so not sure why we would ever need to call a fixed string, as it usually used for specific needs and usually we dont change it
    maybe "fill it", but that we can do in 1 function.

  31. #31
    Lively Member
    Join Date
    Jun 2016
    Posts
    109

    Re: GOSUB - Is it really bad?

    .....yes I know you can replace a GOSUB with a class, but what for? You introduce a new level of complexity only to avoid a GOSUB?
    Instead of 'spaghetti-code' you get 'ravioly-code', does'nt look like much of an improvement to me!

    The same applies to the GOTO statement. I know, you could replace any combination of GOTOs with proper loops. And I know that with several conditional GOTOs it indeed can easily get out of hand.

    So can it with loops.

    May be its just me, but in a complex situation I can follow the GOTOs much more easily than a complex construction of loops. (At least as long as the targets are strictly `local`, i.e. always visible on the same screen)

    In the end, it boils down to: you cannot really hide complexity, you can only shift it around to different places.

  32. #32
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,673

    Re: GOSUB - Is it really bad?

    With goto:
    Code:
    Public Function CreateIPicturePngFromMemory( _
                    ByVal pData As Long, _
                    ByVal lSize As Long) As IPicture
        Dim hMem            As Long
        Dim pLocData        As Long
        Dim pIStream        As IUnknown
        Dim tGdipSI         As GdiplusStartupInput
        Dim lGdipToken      As Long
        Dim hGdipImg        As Long
        Dim hDib            As Long
        Dim rc              As RECT
        Dim bI              As BITMAPINFO
        Dim hdc             As Long
        Dim pBitsData       As Long
        Dim bmpData         As BitmapData
        Dim IID_IPicture    As Guid
        Dim picDesc         As PICTDESC
        Dim pIPicture       As IPicture
     
        tGdipSI.GdiplusVersion = 1
        
        If GdiplusStartup(lGdipToken, tGdipSI) Then Exit Function
        
        hMem = GlobalAlloc(GMEM_MOVEABLE, lSize)
        If hMem = 0 Then GoTo CleanUp
        
        pLocData = GlobalLock(hMem)
        If pLocData = 0 Then GoTo CleanUp
        
        memcpy ByVal pLocData, ByVal pData, lSize
        
        GlobalUnlock hMem
        
        If CreateStreamOnHGlobal(hMem, True, pIStream) Then GoTo CleanUp
        If GdipLoadImageFromStream(pIStream, hGdipImg) Then GoTo CleanUp
        If GdipGetImageWidth(hGdipImg, rc.Right) Then GoTo CleanUp
        If GdipGetImageHeight(hGdipImg, rc.Bottom) Then GoTo CleanUp
        
        With bI.bmiHeader
        
            .biBitCount = 32
            .biHeight = -rc.Bottom
            .biWidth = rc.Right
            .biPlanes = 1
            .biSize = Len(bI.bmiHeader)
            
        End With
        
        hdc = GetDC(0)
        If hdc = 0 Then GoTo CleanUp
        
        hDib = CreateDIBSection(hdc, bI, 0, bmpData.scan0, 0, 0)
        If hDib = 0 Then GoTo CleanUp
        
        With bmpData
        
            .Height = rc.Bottom
            .Width = rc.Right
            .PixelFormat = PixelFormat32bppPARGB
            .stride = .Width * 4
        
        End With
        
        If GdipBitmapLockBits(hGdipImg, rc, ImageLockModeUserInputBuf Or _
                              ImageLockModeRead, PixelFormat32bppPARGB, bmpData) Then GoTo CleanUp
        If GdipBitmapUnlockBits(hGdipImg, bmpData) Then GoTo CleanUp
        
        IIDFromString StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), IID_IPicture
        
        picDesc.cbSizeofstruct = Len(picDesc)
        picDesc.hbmp = hDib
        picDesc.picType = vbPicTypeBitmap
        
        If OleCreatePictureIndirect(picDesc, IID_IPicture, True, pIPicture) Then GoTo CleanUp
     
        If Not ModifyIPicture(pIPicture) Then GoTo CleanUp
        
        Set CreateIPicturePngFromMemory = pIPicture
        
    CleanUp:
        
        If hdc Then ReleaseDC 0, hdc
        If hGdipImg Then GdipDisposeImage hGdipImg
        
        If Not pIStream Is Nothing Then
            Set pIStream = Nothing
        Else
            GlobalFree hMem
        End If
        
        If CreateIPicturePngFromMemory Is Nothing Then
        
            If hDib Then DeleteObject hDib
            
        End If
        
        GdiplusShutdown lGdipToken
        
    End Function
    Without goto:
    Code:
    Public Function CreateIPicturePngFromMemory( _
                    ByVal pData As Long, _
                    ByVal lSize As Long) As IPicture
        Dim hMem            As Long
        Dim pLocData        As Long
        Dim pIStream        As IUnknown
        Dim tGdipSI         As GdiplusStartupInput
        Dim lGdipToken      As Long
        Dim hGdipImg        As Long
        Dim hDib            As Long
        Dim rc              As RECT
        Dim bI              As BITMAPINFO
        Dim hdc             As Long
        Dim pBitsData       As Long
        Dim bmpData         As BitmapData
        Dim IID_IPicture    As Guid
        Dim picDesc         As PICTDESC
        Dim pIPicture       As IPicture
     
        tGdipSI.GdiplusVersion = 1
        
        If GdiplusStartup(lGdipToken, tGdipSI) Then Exit Function
        
        hMem = GlobalAlloc(GMEM_MOVEABLE, lSize)
        If hMem Then
            
            pLocData = GlobalLock(hMem)
            If pLocData Then
            
                memcpy ByVal pLocData, ByVal pData, lSize
                
                GlobalUnlock hMem
                
                If CreateStreamOnHGlobal(hMem, True, pIStream) = 0 Then
                    If GdipLoadImageFromStream(pIStream, hGdipImg) = 0 Then
                        If GdipGetImageWidth(hGdipImg, rc.Right) = 0 Then
                            If GdipGetImageHeight(hGdipImg, rc.Bottom) = 0 Then
                
                                With bI.bmiHeader
                                
                                    .biBitCount = 32
                                    .biHeight = -rc.Bottom
                                    .biWidth = rc.Right
                                    .biPlanes = 1
                                    .biSize = Len(bI.bmiHeader)
                                    
                                End With
                                
                                hdc = GetDC(0)
                                If hdc Then
                                
                                    hDib = CreateDIBSection(hdc, bI, 0, bmpData.scan0, 0, 0)
                                    
                                    If hDib Then
                                        
                                        With bmpData
                                        
                                            .Height = rc.Bottom
                                            .Width = rc.Right
                                            .PixelFormat = PixelFormat32bppPARGB
                                            .stride = .Width * 4
                                        
                                        End With
                                        
                                        If GdipBitmapLockBits(hGdipImg, rc, ImageLockModeUserInputBuf Or _
                                                              ImageLockModeRead, PixelFormat32bppPARGB, bmpData) = 0 Then
                                            If GdipBitmapUnlockBits(hGdipImg, bmpData) = 0 Then
                                                
                                                IIDFromString StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), IID_IPicture
                                                
                                                picDesc.cbSizeofstruct = Len(picDesc)
                                                picDesc.hbmp = hDib
                                                picDesc.picType = vbPicTypeBitmap
                                                
                                                If OleCreatePictureIndirect(picDesc, IID_IPicture, True, pIPicture) = 0 Then
                                                    If ModifyIPicture(pIPicture) Then
                                                        Set CreateIPicturePngFromMemory = pIPicture
                                                    End If
                                                End If
                                            End If
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    End If
                End If
            End If
        End If
     
        If hdc Then ReleaseDC 0, hdc
        If hGdipImg Then GdipDisposeImage hGdipImg
        
        If Not pIStream Is Nothing Then
            Set pIStream = Nothing
        Else
            GlobalFree hMem
        End If
        
        If CreateIPicturePngFromMemory Is Nothing Then
        
            If hDib Then DeleteObject hDib
            
        End If
        
        GdiplusShutdown lGdipToken
        
    End Function
    What's better? I prefer the first one (with goto).

  33. #33
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    hahaha, Trick, that's exactly what I was talking about with "indentation taking our code off the screen". That's the ONE place that a GoTo is very useful.

    However, Tubus, when you say, "In the end, it boils down to: you cannot really hide complexity, you can only shift it around to different places", I suspect you may have a battle on your hands with that one.

    Personally, I'm 100% with Tubus on the occasional use of GoSub. When I'm coding, I'll frequently wind up with a module (with a specific complex overarching objective) that has many procedures in it. And then, I'll be writing one of those procedures and have some small task specific to that procedure I need to do three or four times. The example I repeated in post #25 is a perfect example. Here's a screenshot of the form/module that came out of:

    Name:  Spine.jpg
Views: 1421
Size:  52.6 KB

    That module currently has about 70 general (non-event) procedures in it. Why in the world would I want to add more just because I'm irrationally allergic to GoSub? I wound up writing 4 Gosub sets of code in that module, and I'm completely happy with that.

    But I must say that complexity MUST be managed. If we hope (for others or ourselves) to be able to come back to our code and make changes/enhancements, we must put a reasonable amount of effort into keeping our code as organized as we possibly can.

    Best Regards,
    Elroy

    EDIT1: Just as an FYI, that's a spine motion (mocap) protocol whereby we have children with scoliosis go through a series of bending motions to attempt to determine how their scoliosis is affecting their motion.
    Last edited by Elroy; May 14th, 2018 at 07:47 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  34. #34
    New Member gnome_l0rd's Avatar
    Join Date
    May 2018
    Posts
    1

    Re: GOSUB - Is it really bad?

    I concur. it is there so for what reason not utilize it on the off chance that we feel its privilege or look alright or whatever.

    I endeavor to avoid it, this since it is anything but difficult to begin utilizing it excessively, similar to a propensity, considering; gee. would i be able to utilize it now?

    About the Fixed String issue, I just utilize it for particular needs and generally impermanent or inside a capacity.

    To pass it, more often than not the Fixed String is in a UDT as of now.

    Be that as it may, lets say I need to call a capacity to "accomplish something" with the string.

    normally we utilize a sub/work since we require the string to change into something.

    the byref will make a string, we do whatever and return into the settled string,

    here, regardless of whether the string is out of limit it won't make a mistake, we are sheltered.

    on the off chance that we rather need to send it to another settled string, im beyond any doubt we would utilize UDT.

    so not certain why we could ever need to call a settled string, as it generally utilized for particular needs and for the most part we dont transform it

    perhaps "fill it", yet that we can do in 1 work.

  35. #35
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: GOSUB - Is it really bad?

    Welcome gnome_l0rd. Good to have you.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  36. #36
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: GOSUB - Is it really bad?

    Extreme nesting, usually means you're missing a state variable.

    Code:
    Public Function CreateIPicturePngFromMemory(ByVal pData As Long, _
                                                ByVal lSize As Long _
                                                ) As IPicture
        Dim hMem            As Long
        Dim pLocData        As Long
        Dim pIStream        As IUnknown
        Dim tGdipSI         As GdiplusStartupInput
        Dim lGdipToken      As Long
        Dim hGdipImg        As Long
        Dim hDib            As Long
        Dim rc              As RECT
        Dim bI              As BITMAPINFO
        Dim hdc             As Long
        Dim pBitsData       As Long
        Dim bmpData         As BitmapData
        Dim IID_IPicture    As Guid
        Dim picDesc         As PICTDESC
        Dim pIPicture       As IPicture
        Dim hr              As Long
     
        tGdipSI.GdiplusVersion = 1
        
        If GdiplusStartup(lGdipToken, tGdipSI) Then Exit Function
        
        hMem = GlobalAlloc(GMEM_MOVEABLE, lSize)
        If hMem = 0 Then _
            pLocData = GlobalLock(hMem)
            
        If pLocData Then
            memcpy ByVal pLocData, ByVal pData, lSize
            GlobalUnlock hMem
            hr = CreateStreamOnHGlobal(hMem, True, pIStream)
        Else
            hr = True
        End If
        
        If hr >= 0 Then hr = GdipLoadImageFromStream(pIStream, hGdipImg)
        If hr >= 0 Then hr = GdipGetImageWidth(hGdipImg, rc.Right)
        If hr >= 0 Then hr = GdipGetImageHeight(hGdipImg, rc.Bottom)
        If hr >= 0 Then
            With bI.bmiHeader
            
                .biBitCount = 32
                .biHeight = -rc.Bottom
                .biWidth = rc.Right
                .biPlanes = 1
                .biSize = Len(bI.bmiHeader)
                
            End With
            hdc = GetDC(0)
        End If
        
        If hdc Then hDib = CreateDIBSection(hdc, bI, 0, bmpData.scan0, 0, 0)
        
        If hDib Then
            With bmpData
            
                .Height = rc.Bottom
                .Width = rc.Right
                .PixelFormat = PixelFormat32bppPARGB
                .stride = .Width * 4
            
            End With
            
            hr = GdipBitmapLockBits(hGdipImg, rc, ImageLockModeUserInputBuf Or _
                                    ImageLockModeRead, PixelFormat32bppPARGB, bmpData)
            
            If hr >= 0 Then hr = GdipBitmapUnlockBits(hGdipImg, bmpData)
            
            If hr >= 0 Then
                    
                IIDFromString StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), IID_IPicture
                
                picDesc.cbSizeofstruct = LenB(picDesc)
                picDesc.hbmp = hDib
                picDesc.picType = vbPicTypeBitmap
                
                hr = OleCreatePictureIndirect(picDesc, IID_IPicture, True, pIPicture)
            End If
            
            If hr >= 0 Then
                If ModifyIPicture(pIPicture) Then
                    Set CreateIPicturePngFromMemory = pIPicture
                End If
            End If
        End If
         
        If hdc Then ReleaseDC 0, hdc
        If hGdipImg Then GdipDisposeImage hGdipImg
        
        If Not pIStream Is Nothing Then
            Set pIStream = Nothing
        Else
            GlobalFree hMem
        End If
        
        If CreateIPicturePngFromMemory Is Nothing Then
        
            If hDib Then DeleteObject hDib
            
        End If
        
        GdiplusShutdown lGdipToken
        
    End Function

  37. #37

  38. #38
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: GOSUB - Is it really bad?

    in the end theres no right or wrong, if we want to use it or not its not up to someone else.
    lets go back to "GoSub", as its actually what this thread is all about, this because fixed strings, goto, doevents, dims are better discussed in their own thread separately.

    so far, some of you think GoSub do have its benefits, while for others including me we can do without.
    ok, lets leave it at that, its not that we need to find a way to make everyone do the same.
    the consensus could be that do whatever, the importance is that it works.

  39. #39
    PowerPoster PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Pontypool, Wales
    Posts
    2,458

    Re: GOSUB - Is it really bad?

    Quote Originally Posted by tubus View Post
    .....yes I know you can replace a GOSUB with a class, but what for? You introduce a new level of complexity only to avoid a GOSUB?
    Instead of 'spaghetti-code' you get 'ravioly-code', does'nt look like much of an improvement to me!

    The same applies to the GOTO statement. I know, you could replace any combination of GOTOs with proper loops. And I know that with several conditional GOTOs it indeed can easily get out of hand.

    So can it with loops.

    May be its just me, but in a complex situation I can follow the GOTOs much more easily than a complex construction of loops. (At least as long as the targets are strictly `local`, i.e. always visible on the same screen)

    In the end, it boils down to: you cannot really hide complexity, you can only shift it around to different places.
    I would personally see that the other way around, in most cases I would consider using a GOSUB as a level of complexity to avoid using a class

  40. #40

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2015
    Location
    Colorado USA
    Posts
    261

    Re: GOSUB - Is it really bad?

    I thought the forum was getting too sedate so I thought I would stir the pot a bit by tossing out the Gosub debate. It's kind of like catnip; our cat knows he wants to stay away but he just can't resist...

    Thanks for the good debate. I hope it got everybody thinking and debating a bit. Good to see the neurons firing over a weekend.

    Mountain Man

Page 1 of 3 123 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width