Exit Sub from inner loop?
#1
Is it "safe" to exit  a subroutine while in a While/Wend loop inside the Sub, or does this cause problems with things like the Stack or "memory leak" etc?  Undecided
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#2
SUBs are fine to exit.  (We even have an EXIT SUB command for them.  https://qb64phoenix.com/qb64wiki/index.php/EXIT)

GOSUBs could end up presenting an issue for you, if you run around exiting them without returning, however, so you might want to be careful with them if you make use of them in your code.
Reply
#3
Thanks Steve.
I was aware of the Exit Sub command, and use it often. It's just when I want to exit a loop AND the sub, that worries me. I can do this in two steps, by exiting the While, then having a provisional exit from the sub, but I wanted to simplify the operation. It sounds like I'll have to do this, for stability.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#4
I've had no issues with EXIT SUB within a loop structure in the SUB, just so long as you're sure that you're done with all SUB operations.
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply
#5
@OldMoses: Thank for that.
I've used it before too, without any issues that I'm aware of. 
I intend to do some testing to see if repeated use will cause problems or not, so then I'll feel safer.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#6
Here's a small test I've just run, which runs a snippet that calls a sub 10000 times, and exits early each time:
Code: (Select All)
Screen 9
For runs = 1 To 100000 '                            run the prog 10000 imes
    Numbers:
    For num = 1 To 10
        Print num; '                               print numbers 1 to 10
    Next
    letters '                                      now call the letters sub
    Print
    Print "Run #"; runs; "finished": Print '      show how many runs completed
Next
Print: Print "The final run should yield the same result as the first:"
Print " 1  2  3  4  5  6  7  8  9  10 ABCDEFGHIJ"
Sub letters
    letrnum = 0
    While letrnum < 26 '                           repeat this loop 26 times
        letr$ = Chr$(letrnum + 65) '
        If letrnum = 10 Then Exit Sub '            Bail out early, after j
        Print letr$; '                             show letter A, then B etc until Z
        letrnum = letrnum + 1 '                    next letter
    Wend
    _Delay .1
End Sub

There was no change in the output, so I assume there was no corruption caused by the early exit. Is this a reasonable assumption?
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#7
Aye.  As I mentioned previously, exiting from a SUB has zero bad repercussions.


Unless...

Code: (Select All)
SUB foo
   FOR i = 1 to 100
      GOSUB fooGosub
   NEXT
   EXIT SUB

fooGosub:
    PRINT i
    IF i = 10 THEN EXIT SUB
    RETURN
END SUB

Now, in the above, you're going to have issues eventually, and some folks would say "SEE?!!  YOUR EXIT SUB EXPLODED THE PROGRAM!!!" -- which isn't *actually* the issue.  The problem is you used an EXIT SUB to exit the sub WITHOUT returning from the GOSUB first.  It's the GOSUB and the lost RETURN which is the true problem, and not the EXIT SUB, but it's still something to know to watch out for, if you ever use the routines in combination like that.  Wink
Reply
#8
(02-03-2023, 12:04 AM)SMcNeill Wrote: Aye.  As I mentioned previously, exiting from a SUB has zero bad repercussions.


Unless...

Code: (Select All)
SUB foo
   FOR i = 1 to 100
      GOSUB fooGosub
   NEXT
   EXIT SUB

fooGosub:
    PRINT i
    IF i = 10 THEN EXIT SUB
    RETURN
END SUB

Now, in the above, you're going to have issues eventually, and some folks would say "SEE?!!  YOUR EXIT SUB EXPLODED THE PROGRAM!!!" -- which isn't *actually* the issue.  The problem is you used an EXIT SUB to exit the sub WITHOUT returning from the GOSUB first.  It's the GOSUB and the lost RETURN which is the true problem, and not the EXIT SUB, but it's still something to know to watch out for, if you ever use the routines in combination like that.  Wink

Sorry, Pete, I think I missed the point (yes, I'm a bit dense), but I ran your sub foo 10000 times (from a loop) and it executed as I expected - counted and displayed 1 to 10, then, from my loop, repeated this flawlessly and without throwing an error.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#9
After 1 minute:


[Image: image.png]


After a few minutes:


[Image: image.png]


And after another small wait:


[Image: image.png]

Now, what's our memory usage look like in those various screenshots?   See the issue now?

Exiting a GOSUB without a corresponding RETURN is a memory leak.  Eventually it's going to add up and cause you issues in one form or another.



Seems the website that hosts our screenshots and images is currently not working. If you try the code below and watch your task manager, you can see the endless cimb of memory.

Code: (Select All)
DO
    foo
LOOP

SUB foo
    FOR i = 1 TO 100
        GOSUB fooGosub
    NEXT
    EXIT SUB

    fooGosub:
    PRINT i
    IF i = 10 THEN EXIT SUB
    RETURN
END SUB

We start at 60MB of ram usage, then go up to 100MB and then keep climbing to 200MB, and then keep going up, up, and up endlessly until the program crashes or you start using swap file memory and writing to your hard drive... until your drive is full and THEN the whole OS probably freezes and crashes....
Reply
#10
(02-03-2023, 02:13 AM)SMcNeill Wrote: After 1 minute:


[Image: image.png]


After a few minutes:


[Image: image.png]


And after another small wait:


[Image: image.png]

Now, what's our memory usage look like in those various screenshots?   See the issue now?

Exiting a GOSUB without a corresponding RETURN is a memory leak.  Eventually it's going to add up and cause you issues in one form or another.



Seems the website that hosts our screenshots and images is currently not working.  If you try the code below and watch your task manager, you can see the endless cimb of memory.

Code: (Select All)
DO
    foo
LOOP

SUB foo
    FOR i = 1 TO 100
        GOSUB fooGosub
    NEXT
    EXIT SUB

    fooGosub:
    PRINT i
    IF i = 10 THEN EXIT SUB
    RETURN
END SUB

We start at 60MB of ram usage, then go up to 100MB and then keep climbing to 200MB, and then keep going up, up, and up endlessly until the program crashes or you start using swap file memory and writing to your hard drive... until your drive is full and THEN the whole OS probably freezes and crashes....

Ahah, got it!
CPU usage stays the same, but memory used climbs, presumably to crash at some stage.
But I think I'm still ok to exit early if no other calls are involved, i.e. the sub has not called another sub or process that's still active?
Wrong! I see it still creeps up in my example.
I guess I'll have to be careful how I exit. Thanks.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply




Users browsing this thread: 5 Guest(s)