Thinking Functionally in .NET by John Stovin
Welcome to this review of the Developer Developer Developer 12 talk “Thinking Functionally in .NET” by John Stovin
I was a bit confused because of a typo on the schedule printout meant the title showed as “Thinking Functionality in .NET” so I didn’t know what to expect from this talk.
John moved from OOP to Functional programming. There are lots of F# tutorials but less material explaining why the paradigm is a good idea in the first place.
I enjoyed this talk because it was as much about the functional paradigm as it was about F#. I previously worked with many F# experts such as Scott Wlaschlin, Dave Fancher and Mark Seemann to produce The Case for F# and I think that article complements this talk pretty well.
“The determined real programmer can write fortran programs in any language” — Ed Post
Milestones
⦁ The Lambda Calculus — Alonzo Church 1936
⦁ Lisp 1958, first compiler 1962
⦁ ‘Can programming be liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs” — John Backus, Turing Award Lecture 1977
⦁ Miranda (1985), Haskell (1990)
⦁ Scala (2001), F# (2005), Clojure (2007)
Functions
Try to write pure functions (no side-effects, preferably not even exceptions, all valid inputs generate a result)
- Keep functions small
- Easy to reason about your code
- Easy to test
- Compose functions to build more complex behaviour
Immutable Data
Single Assignment — Write once, read many
Copy-and-modify as an atomic operation
Improved readability
In F#, reassigment is a code smell
The mutable keyword is big and ugly for a reason: you should rarely use it.
John showed a code sample in C# with public setters. This is not good.
Don’t have public setters. Only assign them on construction
No NULLs
“I call it my billion-dollar mistake It was the invention of the null reference in 1965.” — Tony Hoare about ALGOL
Avoiding Null in C#
- You’re stuck with NULL in C#
- NULL checks everywhere make code harder to read and understand
- Don’t use NULL as default
Alternatives
- Use the NULL Object pattern — create a NULL object with defined neutral behaviour
- Be liberal with [NotNull] attributes on function parameters, and use Code Contracts
- Create an Option<> type (hard without pattern matching)
None of these options are great in C# — usually involves a lot of extra code, but it often better to be explicit
But in a later version of C# we may have not nullable types — not there yet.
Thread Safety
Mutable data can be changed by any thread in your application
A context switch can occur at any time
So no sequence of operations on mutable data can be guaranteed
At any point another thread may change the data you are operating on
Immutable data avoids this — anything ..
Types
Types are more fundamental in F# than in C#. It has Tuples and Records and Discriminating Unions (additive types)
Too much C# code passes naked strings and ints (“stringly typed”)
Wrap them in a type (class or struct)
Make your intent clear
Design types that won’t store an invalid value
Discriminated Union
type Shape =
| Rectangle of float * float
| Circle of float
let area s =
match s with
| Rectangle (x,y) -> x * y
| Circle r -> System.Math.Pi * r * r
let rect = Rectangle(10.0, 5.0)
let circ = Circle 3.0
This is not inheritance.
Pattern Matching
So much better than if(), or even switch()
No Additive Types in C#
⦁ You can use inheritance, but its not as versatile
⦁ You can use typeof(), but you lose expressiveness
Some rudimentary pattern matching in C# 7 but not as sophisticated as in F#.
⦁ Overloaded is operator
⦁ Can match on types
Recursion vs Loops
⦁ for loops need a loop counter, breaking single assignment
⦁ A recursive function is a function that calls itself
⦁ Recursion is often simpler and more elegant (beauty is in the eye of the beholder)
public int Length(IEnumerable seq)
{
int count = 0;
var enumeraor = seq.GetEnumerator();
return RecursiveLength(enumerator, 0);
}
private int RecursiveLength(IEnumerator, int count)
{
if(!enumerator.MoveNext())
return count;
}
⦁ F# will compile tail recursion into loops to prevent stack overflow
⦁ C# won’t
⦁ Only use recursion in C# if you can prove that your recursion will terminate before it blows the stack
Lists and Sequences
⦁ a list is a recursive data structure
⦁ either an empty list of an element and a list
⦁ create a new list by prepending an element onto the head of a list
⦁ recurse by taking the head element until you only have an empty list
Higher-Order Functions
A higher order function is a function that takes another function as an argument
LINQ uses lambdas for Where(), Select(), etc. (or you can pass a function with the right signature)
Check out Reactive Extensions if you haven’t already (says they are brilliant)
Dependency Injection
C# dependency injection — interface-based injection
F# — function specification-based injection
Smaller surface area
Less code — you don’t need to maintain an interface definition
Collection Operations
List and Seq has these operations and more:
Filter(p) — select the items in the list that conform to the predicate p
Map(f) — transform list elements from one type to another by applying function f
Likely to be more efficient than any loop you could write
Lazy evaluation in LINQ is for free. Use LINQ.
LINQ is functional
Reactive Extensions
Give you composability over events
Fantastic for UI code or processing incoming data streams
Railway-Oriented Programming
type Result<’TSuccess,’TFailure> =
| Success of ‘TSuccess
| Failure of ‘TFailure
Think of a function as a set of points.
It can either return Success or Failure
Think of success and failure as different railway tracks.
We can compose functions
As long as each function accepts a Result, and returns one.
Conclusions
- Reasoning about code in a multi-core, multi-threaded environment is hard
- Functional languages give you a level of abstraction above the von Neuman machine
- You can still use these abstractions in non-functional languages
“The determine programmer should write functional code in any language.” — John Stovin
John recommends:
Scott Wlaschin’s F# for Fun & Profit
The F# Foundation http://fsharp.org
Functional Thinking by Neal Ford
Finally Michael Marshall recommends Leif Battermann’s Nuget package “Functional Extensions for C#” and says it has helped him clean up his code a lot.