1. 10
  1.  

  2. 3

    What seems remarkable about this comparison, more than how “verbose” C# is, is how much F# has decided for you. Very often we take default behaviors for granted or without due understanding, which leads to fun bugs and weird outcomes later. I am not sure that this “lack of verbosity” is ultimately a good thing for projects that are not kit or small in nature.

    1. 5

      Most of the things that F# has “decided for you” here are obvious no-brainer stuff that you come to implicitly expect from every immutable type over time. Especially in larger projects, you benefit greatly from pervasive immutability, structural equality, total orderings, generic traversal, etc. These are the same decisions that are made for strings in most languages, but for whatever reason languages in the object-oriented tradition have dominated with the choice of mutability, object identity, no ordering, opaque structures, etc.

      F# only needs to generate a lot of code here because of the implicit assumptions of the runtime. If the CLR was built for F# originally, you’d need to generate this much code (or more!) to get the C# defaults.

      In particular, the CLR provides primitives for field mutation, complex constructors, etc that F# doesn’t want or need. F# needs to generate per-type code that could be provided once, generically in the runtime. Whenever you see codegen like this, it is usually because the internal representations aren’t tuned for generic or implicit treatment. For example, the GC for example knows where all the fields are without custom per-type code to traverse the fields. The the runtime was designed for it, equality and ordering could be provided in the same way!