Not sure why this causes infinite loop - and how to use break / return statements.

Hi - programming noob here :slight_smile:

I have a for loop statement, and its freezing unity. I can only assume this is because of an infinite loop. Can someone tell me why this loop is infinite, and for extra credit, can you help me understand the difference between a break statement and a return statement?

What I am trying to do is:

For every entry in the dictionary xAxisMap with key , I want to check the distance between the GameObject (line) that I passed in, and the GameObject in the dictionary at index cnt. If its greater than one, I dont want to do anything futher, just get out of there. If its not greater than 1, I want to add it to my dictionary.

//check to see if it is near another line in this group, if not - dont add it.
			for(int cnt = 0; cnt < xAxisMap[x].Count; cnt++)
			{
				if(Vector3.Distance(line.transform.position, xAxisMap[x][cnt].transform.position) > 1)
				{
					return;
				}
				
				else
				{
					print ("line added to existing X group" + y);
					//otherwise, add this specific cube "line" to that group.
					xAxisMap[x].Add(line);
				}
			}

So here’s how for loops work:

for(<initial statement>; <condition>; <iterative statement>)
{
    <loop statements>
}

The condition gets executed every time, right before loop statements. The condition must equate to a boolean value. If it is false, the loop statements never gets executed. Example:

for(; false;)
{
    // will never get called.
    Debug.Log("fat chance.");
}

If its true, it will loop over at the end of loop statements:

for(; true;)
{
    // infinite calls.
    Debug.Log("every chance in the world.");
}

The initial statement will execute before condition, but only the first time:

int i = 0;
// initial statement can be any kind of statement
for(Debug.Log ("start"); i < 5;)
{
    Debug.Log ("do something");
    ++i;
}

The iterative statement will execute before condition except for the first time:

int i = 0;
// iterative statement can be any kind of statement
for(Debug.Log ("start"); i < 5; Debug.Log ("iterate"))
{
    Debug.Log ("do something");
    ++i;
}

The condition will always be checked after each loop statements. Let me break down the “usual” for loop:

for(int i = 0; i < 2; ++i)
{

}

When this for loop is “unrolled”, this is the sequence of events:

  • initial statement sets i to 0
  • checks if 0 < 5, which is true
  • executes loop statements
  • iterative statement sets i to 1 now
  • checks if 1 < 2, which is true
  • executes loop statements
  • iterative statement sets i to 2 now
  • checks if 2 < 2, which is false
  • loop statements does not execute; loop ends

Something about your condition keeps it from ever being false, and I can tell you what that is.

Your conditional relies on xAxisMap[x].Count, but Count keeps getting bigger and bigger because you keep adding line to the list every loop. Therefore, cnt will never be a bigger or equal to Count, so the condition will always be true and the loop will never end.

The immediate solution to stop the infinite looping is to save the starting value of Count somewhere else. That way, you use a value that never changes. You can do this either way:

int Count = xAxisMap[x].Count;
for(int cnt = 0; cnt < Count; cnt++)

for(int cnt = 0, Count = xAxisMap[x].Count; cnt < Count; cnt++)

But, from looking at your code, it seems that this isn’t the underlying problem. The underlying problem is faulty logic that stems from the misuse of keywords, which in turn stems from not knowing their mechanics. For that, let’s learn the difference between return and break.

The return keyword is related to functions. If a function has a return type specified that isn’t void, such as int someFunction() below, then return with a value is required. With functions like these, it is manditory that return happens once throughout a code path:

int someFunction()
{
    // will do something if condition is true
    if(condition)
    {
        // do stuff
    }

    // do some other stuff after that.

    // ends with a zero.
    return 0;

    // if you put something here, it will never ever happen
    // you'll get a warning though.
}

int someFunction()
{
    // will end here with 3 if condition is true
    if(condition)
    {
        return 3;
    }

    // if condition is false, does stuff here

    // but if that happens, it must end properly somehow.
    // ends with 4 instead.
    return 4;
}

The other type of return is with a function with no return type, such as void otherFunction(). This return is optional, and you don’t give it a value. If it is used, it will end the function right when its executed:

void otherFunction()
{
    // stuff goes here

    // no need for return
}

void otherFunction()
{
    // function will end here with 3 if condition is true
    if(condition)
        return;

    // if condition is false, do other things

    // stuff goes here
}

The break keyword, on the other hand, is used in loops and switch statements. It will end the loop right then and there, much like return ends functions:

// would probably loop infinitely
for(int i = 0; true; i++)
{
    // but... will only execute five times because of the break.
    if(i < 5)
      break;

    Debug.Log("do stuff");
}

There is one more special keyword used in loops; continue. This one is also like break, but instead of ending the entire loop, it only ends that particular iteration:

 // will print out only the even numbers!
for(int i = 0; i < 10; i++)
{
    if(i % 2 == 1)
        continue;

    Debug.Log(i);
}

I take it you would like to add line in only once, right? This can be done many ways, but I will use this way so that you can learn the proper uses of break and continue:

for(int cnt = 0; cnt < xAxisMap[x].Count; cnt++)
{
    if(Vector3.Distance(line.transform.position, xAxisMap[x][cnt].transform.position) > 1)
    {
        // distance is too long! skip to the next element.
        continue;
    }

    //otherwise, its the right distance and we add it in
    xAxisMap[x].Add(line);

    // end the loop: no need to check the other elements, we got what we wanted.
    break;
}

I hope that helps!