first_page

flippant remarks about F#

Get Programming with F#

F# is the end. This feels like the kind of programming language for an old Microsoft dog like me, retiring to learn new tricks. Before I go on and probably say something not very smart, let me thank the folks that helped me on my F# journey (in order of appearance):

Brian Beckman @lorentzframe: As early as 2007, I was floored by Brian Beckman’s soundbite, “Compositionality controls complexity.” The word “compositionality” is a polite reference to functional programming style in general and F# in Microsoft particular. This revolutionary statement (revolutionary to me) was made in what should be his famous video, “Brian Beckman: Don’t fear the Monad” [YouTube] (in case you are Microsoft employee and an archivist, the original link was http://channel9.msdn.com/ShowPost.aspx?PostID=358968).

Don Syme @dsyme: Don Syme [Wikipedia] evangelized his work on F# from the very beginning. Before Microsoft officially recognized the existence of YouTube, Don Syme was in several MSDN Channel 9 videos such as a 2016, On .NET episode, “Don Syme on F#.”

Jessica Kerr @jessitron: Jessica Kerr is not an F# evangelist but she is an excellent one for Elm. Her GOTO 2016 conference talk set the stage for me to meet a flavor of Elmish called Bolero. It took me about five years to figure this out.

Scott Nimrod @bizmonger: Scott’s YouTube channel about things-mostly-F# dates back to 2013 and I show up around 2017—and I am sure that Scott is more than a little disappointed that it has taken me over five years to officially get on the F# train! Nevertheless, Scott has been a key figure of my F# journey, introducing me to such folks as Ody Mbegbu @odytrice, Houston Haynes @h3techdev and Adam Wright @awright18.

Isaac Abraham @isaac_abraham: Isaac Abraham, his book Get Programming with F#, was the final conk on the head that made the scales fall from my eyes. I was made aware of this book from a recommendation by Houston Haynes in a Twitter Space hosted by Scott Nimrod. Save yourself five years and start with this book!

With sincere thanks to the people with the names above, let me now get flippant:

shut up and start with the |> operator

One of the many things Isaac Abraham does well, is let us know that we should not get intimidated by the massive “Symbol and operator reference.” We should start with the forward pipeline operator, |>, and see how it works with the last argument of a curried function (keep reading and see below).

you are not writing statements in F#

In F# you are writing expressions. For the veteran C# developer, this might sound like you would be writing everything as expression lambdas, making expression trees. I recommend asking Don Syme about this but to me this sounds right except there is no clunky Expression<TDelegate> syntax (and your expressions can be separated by line breaks and whitespace).

To really drive home the fact that F# is expression based is the lack of a return keyword (except when you are using async or task blocks [ 📖 docs]). The last line of your expression is the return value of an F# function (when you are returning nothing—or what we call void in C#—we return (), the unit [ 📖 docs] expression).

you “hate” whitespace in Python?

Should you “hate” the importance of whitespace in Python then you will “hate” its importance in F#.

tuples are first-class citizens in F#

My Isaac-Abraham-led study of tuples in F# shows me that tuples are fundamental to F#. The use of commas in F# is probably expressing a tuple like the two tuples in this typical, DateTime.TryParse expression:

match DateTime.TryParse dateTimeString with
| false, _ -> resultError "dc:date"
| true, dateTime -> Ok dateTime

All .NET TryParse patterns decompose into tuples in F#.

F# bends over backwards for .NET APIs

That DateTime.TryParse expression above is but one example of how much F# recognizes the existence of .NET. It would be a mistake to assume that F# wants to escape or trivialize the .NET ecosystem. It would be better to assume that F# deviates from .NET when it “has not been invented yet” for the CLR [ 📖 docs]. For example, the Hindley-Milner (HM) type system has not been invented yet for .NET but it is the beating heart of F# (see “many of the recent developments in C# were inspired by F#” below).

Another great example of this dedication is the foundational Option.ofNullable function [ 📖 docs] which supports Nullable<T> [ 📖 docs].

before you resort to interfaces or Func<T>/Action<T> delegates, just pass a function

Again, F# bends over backwards for .NET APIs—so it does support interfaces, Func<T> [ 📖 docs] and Action<T> [ 📖 docs]. But this great support can confuse a novice F# developer (like me).

For example, the following F# function is not necessary (when this function will only be used by F# expressions):

let sayHello (hf: Func<string>) = hf.Invoke() |> printfn "%s"

Func<string>(fun () -> "hi") |> sayHello //invocation prints "hi"

We can express an equivalent without Func<string>:

let sayHello (hf: unit -> string) = hf() |> printfn "%s"

(fun () -> "hi") |> sayHello //invocation prints "hi"

We see that we are passing a unit -> string type into sayHello in the latter example. This use of a type is just as effective as an interface or .NET generic delegates. F# wants us to find ways to express intent with types before resorting to interfaces or classes.

F# does not really need LINQ

Because I enjoy using LINQ in C# so much, I made an extensive study of why F# does not really need LINQ during my reading of Get Programming with F#.

when F# is presented as a DSL tool, I think the HTML mini languages are downplayed

According to the great Scott Wlaschin @ScottWlaschin:

Domain-specific languages (DSLs) are well recognized as a technique to create more readable and concise code. The functional approach is very well suited for this.

—“F# for Fun and Profit

In my opinion, libraries like Giraffe.ViewEngine [GitHub] should be in every presentation, showing off the DSL features of F#. (Don Syme, by the way, does refer to HTML DSLs when he presents but we need more presenters with more references). When we couple these F# HTML DSLs with Microsoft’s take on WebAssembly which is Blazor, one (like me) will immediately want to see how F# is married to Blazor. Accordingly, I am currently experimenting with Bolero, a project led by Loïc Denuzière @_Tarmil.

When we couple these HTML DSLs with an F#-to-JavaScript compiler like Fable, we can get honest with ourselves and admit just how much we are very-seasoned-but-not-very-fond of working in an npm-based JavaScript ecosystem where you have to run npm-check [ 📦 package] every three weeks.

many of the recent developments in C# were inspired by F#

Here is an incomplete list of features in C# that clearly ‘come from’ F#:

F# also has its own take on generics (as well as supporting .NET generics) which is a key ingredient in the F# type inference system, the Hindley-Milner (HM) type system. I explore this while reading Isaac Abraham’s “Trusting the compiler” section of his book, Get Programming with F#.

because of over 20 years of object-oriented programming, I incorrectly assumed that polymorphism was confined to OOP

While reading Isaac Abraham’s book (mentioned previously), I was led away from the pages and discovered polytypism and the subject of generic programming. Wow.

two words: discriminated unions

A long-time C-like-language developer in the Microsoft meta-verse would see nothing like the discriminated unions (DUs) of F# unless one delves into Typescript. My notes on F# DUs should drag the typical C# developer through the “muck” or through progressive transformation:

Here is my cryptic-or-stupid sound bite about DUs: Did you ever want to define class hierarchies with regular expressions? We do not use regular expressions with DUs but the syntax might look like it!

when you love seeing your C# class files in alphabetical order then F# will pinch at you

F# code depends on order. F# modules and their contents must appear in order of dependency. This means an IDE supporting F# development must allow you to drag and drop files in the correct order, edit the *.fsproj directly or, sadly, pinch at you. I dare not dream of an IDE that can use background-compilation magic to automatically reorder *.fs* files for you!

This limitation on the IDE experience alone may be the reason why folks just cannot switch to F# from working with C# in Visual Studio exclusively. This was relatively easy for me because I spent years with Visual Studio Code which brought me closer to the file system while the flagship, Visual Studio, is designed to ‘hide’ the file system from the beginner programmer in a friendly way.

F# will immediately eliminate at least two categories of cross-cutting unit tests

Two categories of unit tests will never have to be written for an F# project:

  • testing for null
  • testing for exceptions

Instead of having these tests cross-cutting everywhere almost randomly, these categories of tests would be implied and confined under a clearly-defined ‘input transformation layer’ which is three words I have just smashed together on the fly while writing this sentence. In other words, F# encourages us to define and confine a ‘layer’ in our application where untrusted input is processed. This layer should be relatively small compared to the rest of the Solution. Untrusted input can be null or throw exceptions and our input transformation code is meant to defend against this with Option and Result. Currently, I am naming a domain-specific function, fromInput, as a convention to express input transformation.

What is more sophisticated is how we are encouraged to use types in F# to eliminate even more categories of unit tests. Isaac Abraham explores this in his book Get Programming with F#.

Also, for you lovers of xUnit in the world of C#, check out FsUnit. And, as we get intimate with Option and Result, Ody Mbegbu @odytrice recommends FsToolkit.ErrorHandling [GitHub] which I find extremely helpful.

while day-jobbing in C#, lean toward functional style

I have spent most of the last 20 years writing in C# but I was naturally biased toward functional style. I used to think this was a personal, almost aesthetic preference until Brian Beckman @lorentzframe made me realize that this is also a strategic preference for the sake of professional maintainability and clarity.

In a typical C# code review, I should be looking for these functional-style corrections:

issue recommendation
‘tall’ methods decompose C# methods with too many lines into local functions or extension methods; the names of these smaller chunks of code might reduce the need for comments
blocks of code with nested and/or a succession of for loops is hard to read consider replacing the for loops with LINQ .Select() methods to ‘pipe’ from one set of data to another
disruptive or hard-to-read if blocks use C# pattern-matching which is heavily influenced by F#
wide if conditions decompose into local functions or extension methods
a class has ‘too many’ static methods that get in the way of the instance members in terms of readability consider separating these static methods into extension methods instead of partial classes
it is clear that we should return more than one type from a method but defining a class or interface for these types is overkill return a tuple with named fields from this C# method
the team agrees that we should ‘inject an interface into a method’ but defining a formal interface is overkill use Func<> or Action<> in the method signature, effectively touching upon the Strategy Pattern and recognizing the concept of higher order functions
the team is actually sick of null consider using a C# Option library, like Optional
the team is uncomfortable with throwing exceptions deep in the stack and would rather use ‘railways’ to bubble them up with fine/granular control consider using a C# implementation of Result<> like what is available in Functional Extensions for C# which introduces the concept of Railway Oriented Programming which is a step above the famous “fluent” C# style
a team member is called out for primitive obsession F# is actually designed for primitive obsession but there are ways to approach it constructively in C#

https://github.com/BryanWilhite/