F# under the covers X -- the curious case of record types
This is unchanged in the February 2010 CTP (1.9.9.9) release.
They're coming thick and fast now...
Define a record type such as
type internal Context = { | |
Line : int; | |
Column : int; | |
EndLine : int; | |
EndColumn : int } |
The class that results looks like
[Serializable, CompilationMapping(SourceConstructFlags.RecordType)] | |
public sealed class Context : IStructuralEquatable, IComparable, IStructuralComparable | |
{ | |
// Fields | |
[DebuggerBrowsable(DebuggerBrowsableState.Never)] | |
internal int Column@; | |
[DebuggerBrowsable(DebuggerBrowsableState.Never)] | |
internal int EndColumn@; | |
[DebuggerBrowsable(DebuggerBrowsableState.Never)] | |
internal int EndLine@; | |
[DebuggerBrowsable(DebuggerBrowsableState.Never)] | |
internal int Line@; | |
// Methods | |
public Context(int line, int column, int endLine, int endColumn); | |
[CompilerGenerated] | |
public sealed override int CompareTo(object obj); | |
[CompilerGenerated] | |
public int CompareTo(Context obj); | |
[CompilerGenerated] | |
public sealed override int CompareTo(object obj, IComparer comp); | |
[CompilerGenerated] | |
public sealed override bool Equals(object obj); | |
[CompilerGenerated] | |
public bool Equals(Context obj); | |
[CompilerGenerated] | |
public sealed override bool Equals(object obj, IEqualityComparer comp); | |
[CompilerGenerated] | |
public sealed override int GetHashCode(); | |
[CompilerGenerated] | |
public sealed override int GetHashCode(IEqualityComparer comp); | |
// Properties | |
[CompilationMapping(SourceConstructFlags.Field, 1)] | |
public int Column { get; } | |
[CompilationMapping(SourceConstructFlags.Field, 3)] | |
public int EndColumn { get; } | |
[CompilationMapping(SourceConstructFlags.Field, 2)] | |
public int EndLine { get; } | |
[CompilationMapping(SourceConstructFlags.Field, 0)] | |
public int Line { get; } | |
} |
where the source context for each method is the same -- the range containing just the type name.
Now, you wouldn't expect anything to be seriously unusual about this class in terms of its implementation, but there is.
FxCop reminds you about the IComparable
should-haves that can't be enforced through interface constraints:
[Location not stored in Pdb] : warning : CA1036 : Microsoft.Design : 'Context' should define operator '!=' since it implements IComparable. [Location not stored in Pdb] : warning : CA1036 : Microsoft.Design : 'Context' should define operator '<' since it implements IComparable. [Location not stored in Pdb] : warning : CA1036 : Microsoft.Design : 'Context' should define operator '==' since it implements IComparable. [Location not stored in Pdb] : warning : CA1036 : Microsoft.Design : 'Context' should define operator '>' since it implements IComparable.
but which aren't there; and Reflector's decompilation to C# is stymied by the highlighted CompareTo
overloads -- the simple one is implemented as
[CompilerGenerated] | |
public sealed override int CompareTo(object obj) | |
{ | |
return this.CompareTo((Context) obj); | |
} |
which fortunately doesn't give much scope for things to go wrong.
In this and the previous case, the offending instruction that Reflector balks at is a simple branch such as indicated in this example
L_0045: ldc.i4.m1 | |
L_0046: nop | |
L_0047: br.s L_0050 | |
L_0049: ldloc.s num2 | |
L_004b: ldloc.s num3 | |
L_004d: cgt | |
L_004f: nop | |
L_0050: stloc.2 |
It's quite clear at every turn that F# is coming at the problem of code generation from a very different direction to the well explored parts of the phase space of valid IL that C# and VB.net dabble in. And clear, too, that this will present a significant challenge to all writers of tools to work with the language -- it takes us well out of our old comfort zone.
No comments :
Post a Comment