The C# compiler is a pretty good thing, but it has limitations. One limitation that has given me a headache this evening is its inability to guard against cycles in structs. As I learn to think and programme in a more functional style, I find that I am beginning to rely more and more on structs to pass data. This is natural when programming in the functional style, but structs can be damned awkward blighters.

Here is a classic gotcha. The following code won’t compile, and in this case, the compiler does its job and tells you why with a nice CS0523 error:

struct Struct1
{
public Struct2 AStruct2 { get; set; }
}

struct Struct2
{
public Struct1 AStruct1 { get; set; }
}

Structs are value types and are automatically instantiated and initialized as stack objects. If this code were compiled and run, Struct1 would be initialised with a Struct2 which would be initialised with a Struct1 which would be initialised with a Struct2, etc., etc. We would blow the stack.

Well, actually, if the compiler didn’t capture this error, we wouldn’t get a stack overflow because at runtime the type loader would spot the problem and refuse to load the Struct1 type. I know this because the compiler does a really rather poor job of spotting cycles. For example, if you define generic members on your structs things can easily go awry. I have an example of this, but it would take a lot of explaining as to why I wrote the code the way I did (believe me, I had reason to), so instead I’ll provide a much simpler example. Here is a daft attempt to avoid the cycle using a nullable type:

struct Struct1
{
public Struct2? Struct2 { get; set; }
}

struct Struct2
{
public Struct1 Struct1 { get; set; }
}

Of course, this won’t work (duh – so why did I try?). System.Nullable<T> is, itself, a struct, so it does not solve the problem at all. We have simply wrapped one struct in another. However, the C# compiler can’t see the problem. The code will compile just fine. At run-time it will blow up in your face with a ‘Could not load type <T> from assembly’ (80131522) error. Very nasty.

By and large, I get on well with the C# compiler. However, this is one area where there is room for improvement.