F# under the covers III
To date we've seen examples where some simple F# code maps to something horrid in the C# view we get from Reflector.
Now for something completely different...
Simple properties like
[<DefaultValue(true)>] | |
val mutable private points : int | |
member self.Points with get() = self.points and set(v) = self.points <- v |
map quite directly from F# into IL, even in debug build
.method public specialname instance void set_Points(int32 v) cil managed | |
{ | |
.maxstack 4 | |
L_0000: nop | |
L_0001: ldarg.0 | |
L_0002: ldarg.1 | |
L_0003: stfld int32 Tinesware.InfrastructureTests.CoverageExemptionTest::points | |
L_0008: ret | |
} | |
.method public specialname instance int32 get_Points() cil managed | |
{ | |
.maxstack 3 | |
L_0000: nop | |
L_0001: ldarg.0 | |
L_0002: ldfld int32 Tinesware.InfrastructureTests.CoverageExemptionTest::points | |
L_0007: ret | |
} |
where set_Points
just assigns straight into the field, and get_Points
just returns it, roughly as expected.
The corresponding C#
private int points; | |
public int Points { get { return points; } set { points = value; } } |
becomes
.method public hidebysig specialname instance void set_Points(int32 'value') cil managed | |
{ | |
.maxstack 8 | |
L_0000: nop | |
L_0001: ldarg.0 | |
L_0002: ldarg.1 | |
L_0003: stfld int32 Tinesware.TestData.Class1::points | |
L_0008: ret | |
} | |
.method public hidebysig specialname instance int32 get_Points() cil managed | |
{ | |
.maxstack 1 | |
.locals init ( | |
[0] int32 CS$1$0000) | |
L_0000: nop | |
L_0001: ldarg.0 | |
L_0002: ldfld int32 Tinesware.TestData.Class1::points | |
L_0007: stloc.0 | |
L_0008: br.s L_000a | |
L_000a: ldloc.0 | |
L_000b: ret | |
} |
The set_Points
code is the same, modulo the maxstack -- but what are that temporary and that branch doing in get_Points
?
This is a bit of a "lolwut!?" discovery!
Reassuringly, the release build of the C# get_Points
is almost a nop
-free version of the F# debug code
.method public hidebysig specialname instance int32 get_Points() cil managed | |
{ | |
.maxstack 8 | |
L_0000: ldarg.0 | |
L_0001: ldfld int32 Tinesware.TestData.Class1::points | |
L_0006: ret | |
} |
but as the debug version is the one for doing code analysis on, that's less useful.
This is unchanged with the Feb 2010 CTP (1.9.9.9).
1 comment :
The added IL instructions are meant to better support debugging (the jump makes it easier to set breakpoints, and the temp local makes it possible to add a watch on the value and change it).
There's a lot of fluff added to a C# debug build to support these kind of scenarios. Not so much in F#, it seems.
Post a Comment