Can we use just the native .NET classes for developing code, rather than immediately writing an application specific class that often is little more than a container? Can we do this using aliases, a fluent style, and extension methods? If we’re going to just use .NET classes, we’re going to end up using generic dictionaries, tuples, and lists, which gets unwieldy very quickly. We can alias these types with
using statements, but this means copying these using statements into every .cs file where we want to use the alias. A fluent (“dot-style”) notation reduces code lines by representing code in a “workflow-style” notation. In C#, if we don’t write classes with member methods, then we have to implement behaviors as extensions methods. Using aliases improves semantic readability at one level at the cost of confusing generic type nesting in the alias definition. Extension methods can be taken too far, resulting in two rules: write lower level functions for semantic expressiveness, and avoid nested parens that require the programmer to maintain a mental “stack” of the workflow. In contrast to C#’s
using aliases, F# type definitions are not aliases, they are concrete types. New type definitions can be created from existing types. Type definitions can also be used to specify a function’s parameters and return value. The forward pipe operator
|> is similar to the fluent “dot” notation in C#, but the value on the left of the
|> operator “populates” the last parameter in the function’s parameter list. When functions are written that return something, the last function must be piped to the ignore function, which is
slightly awkward. F# type dependencies are based on the order of the files in the project, so a type must be defined before you use it. In C#, creating more complex aliases get messy real fast — this is an experiment, not a recommendation for coding practices! In F#, we don’t need an Action or Func class for passing functions because F# inherently supports type definitions that declare a function’s parameters and return value — in other words, everything in functional programming is actually a function. Tuples are a class in C# but native to functional programming, though C# 6.0 makes using tuples very similar to F#. While C# allows function parameters to be null, in F#, you have to pass in an actual function, even if the function does nothing. F# uses a nominal (“by name”) as opposed to structural inference engine, Giving types semantically meaningful names is very important so that the type inference engine can infer the correct type. In C#, changing the members of class doesn’t affect the class type. Not so with F# (at least with vanilla records) — changing the structure of a record changes the record’s type. Changing the members of a C# class can, among other things, lead to incorrect initialization and usage. Inheritance, particularly in conjunction with mutable fields, can result in behaviors with implicit understanding like “this will never happen” to suddenly break. Extension methods and overloading creates semantic ambiguity. Overloading is actually not supported in F# – functions must have semantically different names, not just different types or parameters lists. Object oriented programming and functional programming both have their pros and cons, with some hopefully concrete discussion presented here.
Full article on Code Project here.