1. Computing & Technology
Avoiding the Recursion Black Hole
Question: Why Did My VB 6 Program Run Out Of "Stack Space"?
 Join the Discussion
Add to the FAQ!
Discuss this at the
About.Com Forum
 
 Other Articles with
Peter Zilahy Ingerman
• Getting Your System Out
• Calculating a Contrasting Color Code
• Symbolic Logic
 

RecursionThis started with
a very simple problem.

I had a bunch of data, of three types (call the types "1", "2", and "3", just to make life simple). I wanted to select the data for processing by using a checkbox, and checking the type I wanted to play with.

I couldn't use radio buttons, because I might want to process more than one type at a time - so I had to use checkboxes.

Being a purist, I also thought it would be nice to have a fourth checkbox indicating "All". And, of course, logically, if I checked "All" then the other three checkboxes should be unchecked, while if I checked one (or more!) of the other three checkboxes, then "All" should be unchecked.

And in order to put all of this logic in one place, I decided to have the four checkboxes be a control array; "All" would have the index 0, and "1", "2", and "3" would be indexed with 1, 2, and 3, respectively.

So I wrote the obvious code:

Private Sub chkDir_Click(Index As Integer)
    If (chkDir(1).Value = vbChecked) _
            Or (chkDir(2).Value = vbChecked) _
            Or (chkDir(3).Value = vbChecked) Then
        chkDir(0).Value = vbUnchecked
    Else
        chkDir(0).Value = vbChecked
    End If
    
    If (Index = 0) Or ((chkDir(1).Value = vbChecked) _
            And (chkDir(2).Value = vbChecked) _
            And (chkDir(3).Value = vbChecked)) Then
        chkDir(0).Value = vbChecked
        chkDir(1).Value = vbUnchecked
        chkDir(2).Value = vbUnchecked
        chkDir(3).Value = vbUnchecked
    End If
End Sub

Looks pretty good. If any of boxes "1", "2", or "3" are checked, then box "0" is forced to be unchecked. If box "0" is checked, or if all of boxes "1", "2", and "3" are checked, then make sure that box "0" is checked and none of the other boxes are checked.

KaPow!

I ran out of stack space.

"Hunh?", I said to myself. Then I realized that I had been snagged by Visual Basic's doing its very best to be helpful. Most of the time this is a Good Thing, but here was a case where it was doing me in.

It turns out that changing the value of a checkbox fires the Click event for the checkbox, since of course (according to Visual Basic), that's what I wanted to do.

Not this time, thank you very much!

The solution is, actually, quite simple.

I defined a variable called NoRecurse (a Boolean) that was global to the form. In the Form_Initialize event I set NoRecurse to False. That took care of the initialization.

I then modified the code as follows:

Private Sub chkDir_Click(Index As Integer)
    If NoRecurse Then Exit Sub
    
    NoRecurse = True
    
    If (chkDir(1).Value = vbChecked) _
            Or (chkDir(2).Value = vbChecked) _
            Or (chkDir(3).Value = vbChecked) Then
        chkDir(0).Value = vbUnchecked
    Else
        chkDir(0).Value = vbChecked
    End If
    
    If (Index = 0) Or ((chkDir(1).Value = vbChecked) _
            And (chkDir(2).Value = vbChecked) _
            And (chkDir(3).Value = vbChecked)) Then
        chkDir(0).Value = vbChecked
        chkDir(1).Value = vbUnchecked
        chkDir(2).Value = vbUnchecked
        chkDir(3).Value = vbUnchecked
    End If
    
    NoRecurse = False
End Sub

So the first time I call chkDir_Click it does all of the things I want it to do, but it also sets NoRecurse to True, so any further attempt to enter chkDir_Click will simply bounce out of the subroutine without doing anything.

Voilá. No more stack overflow problems.

Discuss in my forum

©2012 About.com. All rights reserved.

A part of The New York Times Company.