# C#: Functional warts

## Wart 1: null

Tony Hoare invented the null pointer and later apologised for doing so:

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

**Null breaks parametricity.** In the presence of null an implementation of
the following type cannot assume that `x`

is always a value of type `T`

because the domain of `T`

in C# includes all values of type `T`

**and** the
null pointer.

string Mystery<T, TJsonShow>(T x) where TJsonShow : IJsonShow<T>

Null breaks more than parametricity. It makes it difficult to reason in a
principled way about monomorphic functions too. An implementation of the type
`string Mystery(string x)`

cannot assume that `x`

is a string because the set of
inhabitants of the `string`

type in C# includes null.

## Wart 2: reflection

**Reflection breaks parametricity.** Reflection enables recovering type
information at runtime. With that capability, a type like `Mystery`

below cannot
provide the guarantees that parametric types should give.

string Mystery<T, TEq>(T x, T y, TEq eq) where TEq : IEqualityComparer<T>

Without reflection, `Mystery`

is guaranteed to only ever call the
`IEqualityComparer`

methods on `eq`

. With reflection, `Mystery`

can do just
about anything, like the following crazy implementation does.

string Mystery<T, TEq>(T x, T y, TEq eq) where TEq : IEqualityComparer<T> { if (x is int) return "x is an int"; if (x is string) return ((string) x).ToUpper(); return eq.Equals(x, y).ToString(); }

Trivially, `default(T)`

also breaks parametricity by enabling construction of
values outside the presence of a `new()`

constraint. It does this from type
information gained at runtime, hence, reflection.

## Wart 3: object methods

**Object methods break parametricity.** In C# every type inherits from object.
This means methods on object are callable on values of parametric type
parameters, even when that makes no sense.

For example. Every value except null has a `ToString`

method, which means this
function has an implementation that uses its argument.

string Mystery<T>(T x)

Without object methods (and any of the other warts in this post), there is only
one kind of implementation of `Mystery`

: one that returns a constant string
without touching `x`

.

string Mystery<T>(T x) { return "asdf"; }

With object methods, implementations like the following are possible.

string Mystery<T>(T x) { return x.ToString(); }

This second implementation is problematic because it is defined on any `T`

,
including types for which `ToString`

does not make sense. It should really be
typed something like the following, where the interface `IString`

provides the
`ToString`

method.

string Mystery<T>(T x) where T : IToString

Or, to use the previous post’s type class encoding:

string Mystery<T, TToString>(T x, TToString str) where TToString : IToString<T>

## Wart 4: mutation

Mutation interferes with equational reasoning. Variables in mathematics are
immutable. In the function `f(x) = x * x`

, `x`

is called a variable, not because
the equation can mutate its value, but because the equation can be evaluated for
different values of `x`

. Evaluate `f(3)`

: `f(3) = 3 * 3 => f(3) = 9`

. Evaluate
`f(a + 2)`

: `f(a + 2) = (a + 2) * (a + 2) => f(a + 2) = a^2 + 4a + 4`

. Once the
value of `x`

is known it can be substituted wherever `x`

appears. If `x`

were
mutable and the implementation of `f`

mutated it, evaluation by substitution
would not work; instead the equation would have to be run or stepped through to
work out what it was doing.

Programs that avoid mutation are easier to reason about. A trivial example is
equality. Assuming immutability, if `x == y`

now, `x == y`

always. With
mutation, if `x == y`

now, there is no guarantee that in **n** clock cycles ```
x !=
y
```

because one or both of them was mutated in the meantime. An equality relation
between mutable values is somewhat nonsensical.

Another example is validation. Let `bool IsValid<T>(T x)`

be a function that
determines whether a `T`

is valid according to some specification. If `x`

is
immutable a `true`

return value from `IsValid(x)`

guarantees that `x`

is valid
**forever**: `x`

can be used anywhere a valid `T`

is required. If `x`

is mutable
there is no such guarantee, and if `x`

is mutable and more than one thread has
access to it, all bets are off.

## Wart 5. side effects

Similar to mutation, side effects mess with equational reasoning. Without
mutation and side effects, `string Mystery(int x)`

will always return the same
for any value of `x`

.

Mystery(3) == Mystery(3) // guaranteed

With side effects this guarantee vanishes. For example, none of the following implementations fulfill the above guarantee because their return value depends on external state which may change between calls.

string Mystery1(int x) { return DateTime.Now.AddSeconds(x).ToString(); } string Mystery2(int x) { return string.Join( ",", File.ReadLines("C:\\Windows\\win.ini").Take(x)); }

Five warts are enough for one day.