Mid-2018, after quite some time spent in C# and Azure lands I decided it was time for a change. The next job, I said to myself, is going to have at least one new tech element to it. So, early in 2019 I joined a new company called Jet.com. [You can find some amazing blog posts written by my colleagues at the Jet Tech Blog.]
The things that attracted me at Jet were the tech stack and the scale. I finally got to use a functional language such as F# in production. To be completely honest, before this position, functional languages always seemed like a niche to me. Besides, languages like C# have ingested a lot of functional features to make them better. As you might expect, 3 months in, my views are starting to change.
So what did I learn in the last months and what do I think about F#? That’s my list so far (guaranteed to be revised in another 3 months!):
- For a person grown on Pascal and C-like languages, F# syntax looks odd for the first “many” weeks. It takes time to adjust to the Python-like indentation-based blocks. The presence of the “{ }” brackets is confusing since they are used for quite a few things including “async” code.
- F# is multi-paradigm language on top of .NET. That makes it support things such as classes, for loops and other “not entirely function things“. You can write imperative code in F#. It will look ugly as hell, but you can do it.
- Type inference is crazy! Most of the time you can get away with using a type on anything. C# is seems like a half-baked potato compared to its sibling. The downside becomes apparent when trying to refactor code. One small change in a one function can lead to hundreds of compilation errors as the type inference starts deciding values and arguments have different types.
- It’s all .NET stack so the hard learning curve that one would expect is non a thing (if you come from other .NET languages).
- Works like a charm on .NET Core and docker containers on Linux. [Hard to imagine what Microsoft looks like these days isn’t it?!]
- I have not written one loop yet and I used a recursive function only once. Most of the sequence processing is done using the standard modules and function such as
Seq.map
. - Currying, partial application and other “functions creating functions” concepts are not hard to get around if you used C#’s lambdas and delegates for a while.
- For a person like me that used to write assembler it is hard to let go to the micro-optimizations. One can always write more optimized hand-crafted imperative code. It still takes discipline for me not to drop those immutable
Maps
orlists
in favor of their mutable counterparts. On the other hand, having default immutability on objects makes things much nicer.
These are just my first impressions and I do already sense there is some functionality that I wouldn’t be able t give up in the future!