What do you think is written to the console?
class Program
{
static void Main(string[] args)
{
// Write number to console in worker thread
for (int i = 1; i < 9; i++)
DoLater(() => Console.Write(i));
}
// Call action delegate on separate thread
static void DoLater(Action action)
{
// I'm avoiding using another lambda here to simplify test
new Thread(new ParameterizedThreadStart(DoLater)).Start(action);
}
// Calls the action after waiting for a second
static void DoLater(object action)
{
Thread.Sleep(1000);
((Action)action)();
}
}
If you initially guessed (like me) that it displays the numbers 1-9 in some random order (eg. '14385726') - you'd be wrong... it actually produces '999999999' every time.
So I cranked up .net reflector (I love it) and had a look at my code (optimization set to .NET 1.0 - then translated by me):
private static void Main(string[] args)
{
AutoDelegateClass tmpVar = new AutoDelegateClass();
tmpVar.i = 1;
while (tmpVar.i < 9)
{
DoLater(new Action(tmpVar.Method));
tmpVar.i++;
}
}
This is much more obvious... .net optimizes the lambda expression out of the loop!
Well that was unexpected, but guess what happens when I change main to this:
static void Main(string[] args)
{
for (int i = 1; i < 9; i++)
{
int j = i;
DoLater(() => Console.Write(j));
}
}
This works! ie. it does not optimize the lambda expression out of the loop.
Although confusing at first, it actually makes a lot of sense from the compiler point of view - the initial expression doesn't actually change, since we are referencing a mutable variable... so why not optimize it?
It might be convenient to turn off this optimization programmatically - kind of like a volatile keyword or something, but it's no big deal.
I guess it goes to show that functional code works best with immutable data... and that reflector is way cool.
BTW: The exact same thing occurs in foreach over a collection; and also using classes rather than structs.
No comments:
Post a Comment