Thinking Functionally in .NET by John Stovin

Kevin O'Shaughnessy
5 min readJun 11, 2017

--

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.

--

--

Kevin O'Shaughnessy

Sr. Full Stack Web Dev promoting better professional practices, tools, solutions & helping others.