scopebeef

How can I prevent objects created in a loop from being released at the end of that iteration of the loop


If I'm creating an object and I want it to only last for the current code block, after which it will be destroyed (or at least marked for destruction) automatically, I can use the scope keyword:

using System;

class Program
{
    public void Program()
    {
        let basicString = String("Basic String");

        for (let i = 0 ; i < 4 ; i++)
        {
            let modifiedString = scope String(s);

            if (i%2 == 0)
            {
                modifiedString.ToUpper();
            }
            else
            {
                modifiedString.ToLower();
            }

            Console.WriteLine(modifiedString);

            // modifiedString is marked for destruction 
        }
    }
}

But, if I need the object to remain until after the block, such as for the whole method or for a block outside of the one it was created, how can I specify that scope? For instance, how can I ensure that the strings exist in the second loop below?

using System;
using System.Collections.Generic;

class Program
{
    public void Program()
    {
        let basicString = String("Basic String");

        let modifiedStringList = scope List<String>();

        for (let i = 0 ; i < 4 ; i++)
        {
            let modifiedString = scope String(s);

            if (i%2 == 0)
            {
                modifiedString.ToUpper();
            }
            else
            {
                modifiedString.ToLower();
            }

            modifiedStringList.Append(modifiedString);
            Console.WriteLine(modifiedString);

            // somehow prevent modifiedString from being marked for destruction
        }

        modifiedStringList.RemoveAt(1);

        for (let s in modifiedStringList)
        {
            Console.WriteLine(s);
        }

        // allow all of the modifiedString to be marked for destruction here
    }
}

Solution

  • You can use scope:: to not let the variable be marked for destruction for the entire method:

    using System;
    using System.Collections.Generic;
    
    class Program
    {
        public void Program()
        {
            let basicString = String("Basic String");
    
            let modifiedStringList = scope List<String>();
    
            for (let i = 0 ; i < 4 ; i++)
            {
                // modifiedString won't be destroyed until after Program() exits.
                let modifiedString = scope:: String(s); 
    
                if (i%2 == 0)
                {
                    modifiedString.ToUpper();
                }
                else
                {
                    modifiedString.ToLower();
                }
    
                modifiedStringList.Append(modifiedString);
                Console.WriteLine(modifiedString);
            }
    
            modifiedStringList.RemoveAt(1);
    
            for (let s in modifiedStringList)
            {
                Console.WriteLine(s);
            }
        }
    }
    

    If you need to specify an arbitrary scope between the method and the current block, you can use a named block with BlockName: { ... } and use scope:BlockName:

    using System;
    using System.Collections.Generic;
    
    class Program
    {
        public void Program()
        {
            for (let repeat=0; repeat<10; repeat++)
            RepeatBlock:                
            {
                let basicString = String("Basic String");
    
                let modifiedStringList = scope List<String>();
    
                for (let i = 0 ; i < 4 ; i++)
                {
                    // modifiedString won't be destroyed until after 
                    // the block named RepeatBlock block exits.
                    let modifiedString = scope:RepeatBlock String(s); 
    
                    if (i%2 == 0)
                    {
                        modifiedString.ToUpper();
                    }
                    else
                    {
                        modifiedString.ToLower();
                    }
    
                    modifiedStringList.Append(modifiedString);
                    Console.WriteLine(modifiedString);
                }
    
                modifiedStringList.RemoveAt(1);
    
                for (let s in modifiedStringList)
                {
                    Console.WriteLine(s);
                }
            }
        }
    }