Unchecked.defaultof on a list
f#
Solution
This is pretty amazing question. I looked how F# lists are compiled and it explains the behaviour. I would not consider this as bug (that's why `defaultof` is in the `Unchecked` module, it might as well burn down your computer!)
First of all, the empty list `[]` is not represented as `null` in F# 2.0, because then you would not be able to invoke methods on empty list - and this would break many things (like passing empty list to any `Seq` function). As an aside, the `None` value is represented as `null` for efficiency, which means that `option<'a>` cannot implement the `seq<'a>` interface even though it would make sense.
So instead, F# uses a special value `list.Empty` to represent empty lists. Now this value is an instance of the same type as values representing non-empty list (the type is `FSharpList<'T>`). The only difference is that both `head` and `tail` fields of the instance are `null`.
Now, you can maybe see where this is going - an empty list is essentially compiled to an object where the `this.tail` field is `null` (and the `this.head` field is `null` too, but this is not that important).
The `list.Tail` property will throw an exception when the field `this.tail` is `null` (because this means you're getting the tail of an empty list - which is an error), but there is also an internal property `list.TailOrNull` which returns the value without checking and which is used to compile pattern matching.
For example, here is a simple `iter` function:
let rec iter (xs:int list) =
match list with
| x::xs -> Console.WriteLine(x); iter xs
| [] -> ()
This is compiled to the following C# code:
if (list.TailOrNull != null) {
Console.WriteLine(list.HeadOrDefault);
iter(list.TailOrNull);
}
This checks whether `list` is an empty list by checking whether its `list.TailOrNull` is `null`. If it is then it knows that the current `list` value is the `list.Empty` value representing an empty list (and it does not print its `HeadOrDefault` because it assumes that this is `null` too).
If you use `defaultof` to create `null` value explicitly then `42::null` gives you an object where `TailOrNull` is `null` but `HeadOrDefault` is `42`. So that's why the value is not printed.
TL;DR - Do not use `Unchecked.defaultof` with F# types. You never know what will happen.
Problem
Consider: ``` > Unchecked.defaultof<list<int>>;; val it : int list = null > 2 :: 1 :: Unchecked.defaultof<list<int>>;; val it : int list = [2] ``` What's the reasoning behind this behavior? I would expect the final list to be [2;1] or raise an exception.