Details
Description
Compare the il code for this boo code:
import System.Collections.Generic
x = List[of int] ()
x.Add(1)
x.Add(2)
for i in x:
print i
and this C# code:
using System.Collections.Generic;
class X {
static void Main() {
List<int> x = new List<int>();
x.Add(1);
x.Add(2);
foreach (int i in x) { System.Console.WriteLine(i); }
}}
IL_0015: callvirt instance class [mscorlib]System.Collections.IEnumerator class [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_001a: stloc.2
.try { // 0
IL_001b: br IL_0032
IL_0020: ldloc.2
IL_0021: callvirt instance object class [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0026: call int32 class [Boo.Lang]Boo.Lang.Runtime.RuntimeServices::UnboxInt32(object)
IL_002b: stloc.1
IL_002c: ldloc.1
IL_002d: call void class [mscorlib]System.Console::WriteLine(int32)
IL_0032: ldloc.2
IL_0033: callvirt instance bool class [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0038: brtrue IL_0020
IL_003d: leave IL_005c
IL_0015: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_001a: stloc.2
.try { // 0
IL_001b: br IL_002e
IL_0020: ldloca.s 2
IL_0022: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0027: stloc.1
IL_0028: ldloc.1
IL_0029: call void class [mscorlib]System.Console::WriteLine(int32)
IL_002e: ldloca.s 2
IL_0030: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
IL_0035: brtrue IL_0020
IL_003a: leave IL_0047
} // end .try 0
The C# version uses the value type iterator which is much faster
Issue Links
| This issue is related to: | ||||
| BOO-779 | Use generic IEnumerable interface for compiling for loops when applicable |
|
|
|
Remember that there are three possible GetEnumerator methods:
1) There's List<T>.IEnumerable.GetEnumerator(). This causes the enumerator object to be allocated on the heap, all enumerator method calls to be virtual, and causes boxing for every element in the list.
2) There's List<T>.IEnumerable<T>.GetEnumerator(). This causes the enumerator object to be allocated on the heap, all enumerator method calls to be virtual, but elements don't have to be boxed.
3) There's List<T>.GetEnumerator(), with return type struct List<T>.Enumerator. The enumerator is a value type on the stack, the enumerator method calls are non-virtual, and elements don't have to be boxed. There is no heap allocation at all.
Boo currently uses 1, C# uses 3.