Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

In unity, in C#, I have the following code in Awake():

Awake()
{
    Transform obj = InstantiateTarget();
    //the bizarrely required and "working" loop
    while (transform.childCount > 0)
    {
        //assign all current children to the replacement object
        foreach (Transform t in transform)
        {
            t.parent = obj;
        }
    }

    Destroy(gameObject);
}

Without the while loop, some random set of the transforms children are destroyed by that end Destroy. With the while, it works exactly as expected (all transform's children become obj's children).

Also, surely with it, there should be an infinite loop (if nothing is changing in another thread, as implied by unity docs). This is in Unity 3.5.

Why does it only work with the while loop? And why doesn't unity get stuck in an infinite loop?

share|improve this question
    
"With the while, it works exactly as expected." - Which is? What is the expected output? –  Alex M. Mar 28 '13 at 14:58
    
The expected output: parent all children to obj. The output without the while loop: only some children are parented to obj, some remain parented to transform –  Bomadeno Mar 28 '13 at 15:00
1  
You're getting good answers here, though I believe this belongs on stackoverflow. –  Byte56 Mar 28 '13 at 16:29
1  
Technically, if Unity did not suppress the thrown exception, you would've noticed the issue right away. The answer requires knowledge of this (Unity) bug so, in my opinion, this is the place for the question. –  Alex M. Mar 28 '13 at 17:11
1  
You're iterating over a collection while removing elements from it (which is what changing its parent will do). This is illegal and produces undefined behavior (or oddness like only iterating over a subset of all items in the collection) for most data structures in almost all languages. This is a basic programming question, nothing super specific to games, C#, or Unity. –  Sean Middleditch Mar 30 '13 at 2:59

1 Answer 1

up vote 11 down vote accepted

It's actually Unity's fault for being quite confusing here. You are not allowed to alter a collection that you're enumerating with a foreach loop. Suppose this:

List<string> SomeList = new List<string>();
//add items to the list
foreach (string s in SomeList)
{
    SomeList.Remove(s); //WRONG! You cannot alter the collection here. Use a for loop instead!
}

Normally, this is not allowed in Mono and throws an exception. Unity apparently suppresses it and tells you nothing. Here's what actually happens in your code:

Awake()
{
    Transform obj = InstantiateTarget();
    //While there are no children attached to this transform;
    while (transform.childCount > 0) /*Not an infinite loop
                                     because on each step you're removing
                                     a child from this transform
                                     (read on for the explanation).*/
    {
        //Try to attach each child to obj
        foreach (Transform t in transform)
        {
            t.parent = obj; /*The first "t" gets attached, but you're also 
                            altering the collection (this.transform loses track of t). 
                            The foreach loop stops completely! 
                            Since you're executing the foreach loop for 
                            as long as this.transfom has children, you 
                            essentially remove one child transform at a time on 
                            each 'while' pass.*/
        }
    }
    Destroy(gameObject);
}

Use a for loop instead and, as a rule of thumb, every time you write a foreach loop, ask yourself if you're not actually trying to remove items from the collection. If you are, stop right there and use the for loop instead.

share|improve this answer
5  
C#'s foreach behavior in a nutshell, good catch (pun) on Unity subverting the exception and pretending nothing happened. –  Patrick Hughes Mar 28 '13 at 15:46
1  
Argh, of course! I didn't even think that I was modifying a collection, as I was changing the parent of a member of it. Of course it makes sense that it immediately affect transform, I just didn't connect the dots far enough! Thanks for the enlightenment! –  Bomadeno Mar 28 '13 at 16:34

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.