For loop not working!

My For loop isn’t working! Here’s the code:

if (ToastTimeout > 0)
        {
            for (int i = 0; i < StringGrid.Count; i++)
            {
                StringGrid[length + i].GetComponent<Renderer>().material.SetColor("_Color", new Color32(255, 255, 255, (byte)(255 * ToastTimeout / Scale)));
            }
            ToastTimeout -= Time.deltaTime;
        }

It runs correctly until i is 4, then at the very end of the For loop, it switches back to 0. But there are more than 4 elements in the dictionary StringGrid (Yes, I know they are GameObjects but it’s called StringGrid). It never leaves the For loop, because the condition is never met, and it never runs the line below the For loop, which is crucial.

StringGrid is a dictionary yeah? When you access a dictionary’s indexer with a key that doesn’t exist, it adds a key-value pair for that key. So you are probably just adding infinite members to your dictionary.

Not sure what you’re trying to accomplish here, but you will need to rethink your approach. A regular List collection is probably more appropriate.

You really shouldn’t write lines of code like line 5 in that example, as well. Break it down and make it easier to understand.

Also worth noting that when you access the .material property of a renderer, it creates an instances of that material. You need to destroy this object when no longer needed, otherwise this creates a memory leak.

Needless to say, fundamental language features like for-loops DO work. If they aren’t working, there is something wrong with your code.

3 Likes

If you have more than one or two dots (.) in a single statement, you’re just being mean to yourself.

Putting lots of code on one line DOES NOT make it any faster. That’s not how compiled code works.

The longer your lines of code are, the harder they will be for you to understand them.

How to break down hairy lines of code:

http://plbm.com/?p=248

Break it up, practice social distancing in your code, one thing per line please.

“Programming is hard enough without making it harder for ourselves.” - angrypenguin on Unity3D forums

“Combining a bunch of stuff into one line always feels satisfying, but it’s always a PITA to debug.” - StarManta on the Unity3D forums

I would even add that if you’re at the point where you think the for() loop doesn’t work, then just delete the line of code and re-engineer the solution from first principles, asking yourself the standard questions for any loop: where does it start, where does it end, and what is iterating it?

2 Likes

Like @spiney199 mentioned if you’re a Dictionary and the entry doesn’t exist it’s going to add a new one to the collection. The advantage and disadvantage to a for loop is that you can add or remove entries of a collection and it can change the end condition. If you’re continuously triggering the Dictionary to add new entries with every pass of the loop then Count will continue to rise every pass and the loop becomes infinite.

I do understand this, however I can guarantee this is not the problem I’m having. If it was, i would just keep increasing. However, as it is, it goes up to 4 and then resets. But there are definitely more than 4 elements in that dictionary. Also, as I’m accessing the attributes of each value, I’m fairly sure it won’t create a new value, if it does it would throw an error.

There’s nothing there that would make i reset. Your code likely just has a logical flaw.

Rather than debate whether fundamental aspects of C# work (spoiler alert, they do), perhaps you can try apply our suggestions?

You’re going to have to start debugging then because nothing in that code is incorrect. I’d start with a Debug.Log(StringGrid.Count) in the loop.

1 Like

The length of the count is 7. I am also recording what i does, it goes up to four then just cuts off and doesn’t execute the rest.

Probably helps to define what “cuts off and doesn’t execute the rest” means. Does the application hang entirely? Does it just leave the loop?

Right, it’s in fixedUpdate, so it just doesn’t finish the for loop and instead restarts the fixedupdate loop completely over, never executing the bottom code.

Code… does not work like that.

Loops don’t just not finish, and code doesn’t get skipped unless you specifically return from execution early (either by specifically calling return; or by throwing an exception).

You need to keep debugging to see what’s going on here. Are you sure an exception is not being thrown?

Additionally, why is a dictionary being used here as a opposed to a List? And why is non-physics code being used in FixedUpdate?

1 Like

I moved it to Update, it did the same thing, BUT you did get me to click the “break on all exceptions” button I conveniently missed and found out that the way I indexed the dictionary was by .5 increments and I didn’t account for that. Because it couldn’t find the GameObjects, it threw an error (And did NOT create more pairs as some have said). Now it works!

StringGrid[length + i] will add new item (and in this case, null item) to the dictionary if length + i is not found. This is how dictionary is implemented. So StringGrid.Count will just keep increasing leads to an infinite loop.

I checked that, but the docs note that a new key-value-pair is only made when you assign to the dictionary: Dictionary<TKey,TValue>.Item[TKey] Property (System.Collections.Generic) | Microsoft Learn

If you’re reading from a key that doesn’t exist, you’ll get an exception.

1 Like

Oops, my bad, I’ve just run a test and it really throws a key not found exception.

Funny thing is, I was also under the exact same impression as @Ryiah and @Laicasanne. I wonder where that particular “Mandela Effect” originated?

1 Like

I was too before I double checked myself and found out I was wrong.

I will say, it is weird that getting a value and assigning a value via the key has two different behaviours if the key doesn’t exist. But I guess it was a decision from a long time ago that can’t be changed now.

2 Likes

And I suspect that’s the root of it. My memory is quite distinctly that accessing a non-existent key causes it to be added to the collection. I either did not learn, or have somehow since forgotten, the distinction between read and write access in this case.

1 Like

I believe you’re both probably right, IF I wasn’t accessing attributes of the keys only associated with GameObjects. If I was just accessing them and not their attributes, it would probably have made a new pair.

Well no, it would not have made a difference. Accessing the dictionary at all via the indexer with a key that doesn’t exist, it will throw an exception, as it states in the documentation I linked above:

If the specified key is not found, a get operation throws a KeyNotFoundException, and a set operation creates a new element with the specified key.

So the exception starts and ends value = dictionary[keyNotInDictionary]; and whether you try to do anything with the value after that point is after the exception has been thrown.