Happy New Year! Its been over a year since I started working with F#, Learning the language and improving my skills, looking back I realize that I’ve come a long way from being totally puzzled about the language to now understanding it intuitively and even contributing to the Visual F# Compiler. That said, I decided to write this blog post about things that I wished I knew or that I wished someone had told me before I started this Journey.
1. It is easy to learn
Right off the bat. This is by far the biggest misconception about F#. The idea that F# is difficult to learn. But that’s simply not true. F# strives for symmetry. This means that the language is built on very few powerful low-level constructs/abstractions and the advanced ideas are derived from those.
For example in F#, The let keyword allows you to perform what is called a binding. Once you fully understand the let keyword, you can create functions, values, perform basic pattern matching e.t.c. With the knowledge of the let keyword alone, you can get A LOT of things done. That’s true for a lot of fsharp. Once you learn a few keywords/constructs in F# you can get a lot of things done. Or at the very least it’s easy to understand a lot of things.
In PDC 2008 Luca Bolognese did just that. He taught what is probably the 40% of F# that you’ll use 80% of the time in roughly an hour.
2. It is VERY typesafe
It all boils down to one thing. How much confidence do you have in “Build Succeeded”?
Now imagine re-implementing the said algorithm on the back-end with something like C# with stronger type-safety and much less unpredictable run-time behavior. F# is the next evolution in that chain.
The F# compiler checks for missing cases in logic. With the magic of Type Providers, It can even check and validate connection strings, SQL statements, application settings e.t.c. This almost gives the feeling of “If it builds, either what you are trying to accomplish is wrong or it will work correctly”. The chances of having runtime errors are even smaller.
3. It encourages experimentation
F# comes from a rich history of functional languages. These languages came from Academia as a result, they are designed to be exploratory or should I say “Scripty”. In other words, they encourage experimentation.
F# has a tool called FSharp Interactive (FSI). It’s an environment where the line between compile-time and runtime is blurred. It’s very similar to something like LinqPad in the sense that you can quickly write code and execute them immediately. However, unlike LinqPad, FSI is an interactive space. You run some code, create objects and functions and these things stay in memory. You add some more code and run them and see the results. It’s a very different way of thinking.
In some ways, it’s taking the good ideas behind Test Driven Development (TDD) to their logical conclusion. That’s because when you are done experimenting with the code, you can easily extract the code you’ve “tested” into your application and take the running logic into your tests and then you can repeat the cycle.
Granted, C# now has this feature in what is called C# interactive but in my opinion, it is not as effective as FSI. That’s because F# was designed from the ground up to be used this way. In F# EVERYTHING is an expression, therefore, every piece of an F# program can be evaluated. This is common in scripting languages and it’s interesting to note that F# retains all this while being very strongly typed.
4. It can be very intuitive
The real reason F# looks cryptic at first is that its coming from a different family of languages and we aren’t used to writing code that way. If you are coming from any of the other functional languages like Haskell, OCaml or even python, F# will be very intuitive. Its akin to moving from C++ or Java to C#. The only reason it looks cryptic is that it’s not part of the C-Like Family which has dominated our industry for decades. After about a month of learning, It didn’t seem cryptic at all.
The Symbols in F# have almost universal meanings in the world of functional programming like (>> or |>). It is no more cryptic than !=, == or <>. After the initial “syntax shock” (which is normal by the way) you’ll start to see that a lot of ideas can be expressed in F# quite intuitively.
Also, some problems are much easier to come up with functional solutions because it’s closer to the way we humans think.
Take binding for example, When you say to a layperson that “x = 3”. To them, it means that x is actually 3. Not assigning 3 to x. Another example would be repetition. To “repeat” means to “do again” not increment a variable and check for a condition... Do you see what I mean?
5. It shuns ceremony
In addition to F# encouraging experimentation, the F# language also shuns ceremony. The language was designed to be tight, concise and straight to the point. Unlike “C-like” languages, it shuns curly braces, semi-colons and superfluous keywords like new.
A simple C# program contains a namespace, class and a static method, F# shuns all those and makes them optional. In C# you typically want classes to be public, so in F# they made public the default. That way you don’t need to type public all the time.
At the language level, little things like tuples, records and discriminated unions dramatically cut down the amount of code it takes to express common ideas and concepts.
At a higher level of implementing specific features, F# uses the Type Provider language feature to cut down the amount of ceremony it takes in connecting to a database and using it. Or even fetching data from a REST API amongst other things.
At an architectural level, F# shuns the ceremony of creating an Interface/Implementation pair just to have the ability to hide implementation details. You can simply just pass functions rather than creating an interface that has only one method in it. In other words, the method signature IS the interface. It typically tells you everything you need to know about the function
6. Easier to Test
There is a deeper difference between the Object Oriented and Functional Paradigms. It boils down to Encapsulation vs Composition. I wrote about this in the post “Fitting the pieces together”
Long story short, Functional programming in general focuses on combining smaller isolated things into bigger things.
If you look at the SOLID principles of Object Oriented Design at a very high level, you’ll see that it’s trying to isolate Object Oriented code so that you can test them. The idea of having rich domain objects that had every functionality that we wanted leads to an untestable clog of code.
Functional programming by default lends itself to be easily testable. Partly because every component is already isolated to begin with as opposed to hiding things behind interfaces and having to mock everything.
Mark Seemann did a talk on this “Look, No Mocks! Functional TDD with F#”
That said, Encapsulation is still good for some problems.. an example is building GUIs or Abstract DataTypes (ADT) but we took the encapsulation hammer and used it to knock every problem.
7. VERY Friendly Community
I’ve been part of several communities from Ruby, Angular, NodeJS, C# e.t.c. and so far the F# community has become the gold standard for me in terms of community. They are welcoming and always happy to help. For example, there is the F# mentorship program where an experienced developer will volunteer time to help you get a better grasp of the language and I have benefited immensely from it. Like seriously, can you show me any community that does this?
There’s also the Slack community where you can meet and discuss with other community members.
8. It will open your mind to possibilities
F# has a lot of tools in its toolbox. For example, Something as simple as a discriminated union has no direct mental translation in C# and Java. The closest explanation is a class hierarchy. But that doesn’t explain much. However, It is a very powerful tool when modeling domains. If you haven’t used it, It’s difficult to show you the value the same way it’s difficult to show a Pascal/C programmer the value of a class in Java.
Learning F# will help make you a better programmer overall not just in C# or Java. You will see new patterns for solving problems and it helps you to mature your skills.
Conclusion — Don’t be Afraid
Ultimately the most important thing I wished someone had told me is.. “Don’t be afraid”. Being a self-taught developer, I don’t consider myself a Maths wizard. I’ve always had the idea that F# is good for Mathematicians. But in the end, It’s just a .NET Language like Powershell.
PS — Speaking of Powershell, I had absolutely no problems learning Powershell. That’s funny because F# and Powershell share A LOT in common. Its also a functional, scripting language with similar features like pipelining, shadowing, composition e.t.c. and yet I was able to pick it up in very little time.