F#, C#, and dotPeek

As development continues on Arcana ERP, we see that in order to fulfill our design goals of high availability and distributed concurrency, portions of ArcanaErp.Core are being re-written piece by piece in F# (a general purpose functional programming langauge, targeting .NET, and originally developed at Microsoft Research, Cambridge).

An interesting outcome of this experiment is that we can see concise, expressive, and terse idiomatic F# "expand" into equivalent, and more verbose, C#:

F# Source

namespace ArcanaErp.Core.Lambda

open System

module Interfaces =

    type IBaseErpModel =
        abstract member Id : int with get, set
        abstract member Description : string with get, set
        abstract member ExternalIdentifier : string with get, set
        abstract member ExternalIdSource : string with get, set
        abstract member CreatedAt : DateTime with get, set
        abstract member UpdatedAt : DateTime with get, set

dotPeek'd C#

using Microsoft.FSharp.Core;  
using System;

namespace ArcanaErp.Core.Lambda  
{
  [CompilationMapping(SourceConstructFlags.Module)]
  public static class Interfaces
  {
    [CompilationMapping(SourceConstructFlags.ObjectType)]
    [Serializable]
    public interface IBaseErpModel
    {
      int Id { get; set; }

      string Description { get; set; }

      string ExternalIdentifier { get; set; }

      string ExternalIdSource { get; set; }

      DateTime CreatedAt { get; set; }

      DateTime UpdatedAt { get; set; }
    }
  }
}

A Bigger Example

First, in F#

The previous example was fairly straightforward. We see some extra curly braces and some attributes we can get rid of. Here is a sample from the FSharp.Core assembly in the Microsoft.FSharp.Collections namespace:

        [<CompiledName("IterateIndexed")>]
        let iteri f (source : seq<'T>) = 
            checkNonNull "source" source
            use e = source.GetEnumerator()
            let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
            let mutable i = 0 
            while e.MoveNext() do
                f.Invoke(i, e.Current);
                i <- i + 1;

Decompiled to C#

    [CompilationArgumentCounts(new int[] {1, 1})]
    [CompilationSourceName("iteri")]
    public static void IterateIndexed<T>(FSharpFunc<int, FSharpFunc<T, Unit>> action, IEnumerable<T> source)
    {
      if ((object) source == null)
        throw new ArgumentNullException("source");
      System.Collections.Generic.IEnumerator<T> enumerator = source.GetEnumerator();
      try
      {
        OptimizedClosures.FSharpFunc<int, T, Unit> fsharpFunc = OptimizedClosures.FSharpFunc<int, T, Unit>.Adapt(action);
        int num = 0;
        while (enumerator.MoveNext())
        {
          fsharpFunc.Invoke(num, enumerator.Current);
          ++num;
        }
      }
      finally
      {
        IDisposable disposable = enumerator as IDisposable;
        if (disposable != null)
          disposable.Dispose();
      }
    }

Wrapping Up

It is clear to see that F# is the winner here. The F# code is more compact, more expressive, and easier to reason about (after, admittedly, a small learning curve on the F# syntax).

Writing software as complex as an ERP systems, and enterprise software in general, requires code that can be reasoned about fairly easily. On all accounts, for us, F# makes sense.