How F# record types translate to C# code

22 Jun 2012

Here's another useful insight from Ivan Towlson's A Practical Developer's Introduction to F#.

Suppose you want to store information about a person in F#, then the build-in record type provides a nice way of grouping related data together:

type Person = { Name: string; Age: int }

Decompiling the generated IL and coming at it from a C# angle provides for an interesting exercise. It not only shows how terse F# can be, but also how easy it is to consume F# types from other .NET languages (decompiled IL is method signatures only, not actual implementation):

[Serializable, CompilationMapping(SourceConstructFlags.RecordType)]
public sealed class Person : IEquatable<Person>, IStructuralEquatable, IComparable<Person>, 
                             IComparable, IStructuralComparable {
    // Fields
    [DebuggerBrowsable(DebuggerBrowsableState.Never)] internal int Age@;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)] internal string Name@;

    // Methods
    public Person(string name, int age);
    [CompilerGenerated] public sealed override int CompareTo(Person obj);
    [CompilerGenerated] public sealed override int CompareTo(object obj);
    [CompilerGenerated] public sealed override int CompareTo(object obj, IComparer comp);
    [CompilerGenerated] public sealed override bool Equals(Person obj);
    [CompilerGenerated] public sealed override bool Equals(object 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 Age { get; }
    [CompilationMapping(SourceConstructFlags.Field, 0)] public string Name { get; }

Observe how a public constructor has been generated, accepting arguments in the order in which the record was defined, and how only getter properties for Name and Age exist. That's because the record type is immutable. The value of Person can only be set once using the constructor. Finally, compare, equals, and hash code methods for doing value comparisons, implementing all the proper interfaces, have been compiler-generated as well.