Log in

Leonard Sperry

Whimsical musings of a Software Engineer, Seattlite, and Father

Discovering Scope with Value Types and Reference Types

by Leonard

Ok, here's a brain bender for you.  It's a twist on a C# puzzle I've seen before.  Instead of one loop, there are 3.

using System;

namespace What
{
    class Program
    {
        static void Main(string[] args)
        {
            Action a = null;

            for (int i = 0; i < 10; i++)
            {
                a += () => Console.WriteLine(i);
            }

            for (int i = 0; i < 10; i++)
            {
                a += new Func<int, Action>((intParam) => 
                    new Action(() => Console.WriteLine(intParam)))(i);
            }

            for (MyInt i = 0; i < 10; i++)
            {
                a += new Func<MyInt, Action>((intParam) => 
                    new Action(() => Console.WriteLine(intParam)))(i);
            }

            a();

            Console.ReadLine();
        }
    }

    class MyInt
    {
        int InternalInt { get; set; }

        public static implicit operator int(MyInt i)
        {
            return i.InternalInt;
        }

        public static implicit operator MyInt(int i)
        {
            return new MyInt() { InternalInt = i };
        }

        public static MyInt operator ++(MyInt i)
        {
            i.InternalInt++;
            return i;
        }
    }
}

The output for this is

10
10
10
10
10
10
10
10
10
10
0
1
2
3
4
5
6
7
8
9
10
10
10
10
10
10
10
10
10
10

 The first loop is the one I'd seen before.  At first glance most people say it prints out 0-9.  You have to remember that a is a multicast delegate that does not get run until the very end. 

So which version of i is getting printed?  The first version, and by that I mean that there are 3 seperate variables called i in the program.  Each only has scope within the for loop that it is defined in.

So if it doesn't have scope, what get's printed at the end?  Even though i is not in scope when a gets called, the actions stored in a are holding a reference to it.

The second loop is a successfull attempt to make it print out 0-9.  a is assigned the result of a function that returns an action.  When the function is executed it is passed i to create the action. When it is passed, (i is a value type) a copy of it is created.

The third loop is identical to the second with one very important difference. A class called MyInt is used instead.  There is some fancy code in MyInt but it is just there to help it behave like an int.  The important thing is that it is a class and all classes are reference types, which means that no copy is ever made.


TAGS: ,

Code

blog comments powered by Disqus

About the author

Leonard is a Software Engineer who works for a web CMS firm in Seattle Washington.  He is the primary technical contractor for Seattle Engraving.   Where he built a custom CRM to help manage customer interactions and will soon be rolling out a new and improved website based on Orchard CMS.

He has lived in the Puget Sound region for most of his life, and is a father of 3.

Month List