8
public struct Unit
{
    Unit u;
}

Causes:

Struct member 'Unit.u' of type 'Unit' causes a cycle in the struct layout.

But

public class Unit
{
    Unit u;
}

compiles. I understand the problem I suppose. An endless cycle will be formed when referencing a Unit object since it will have to initialize another member Unit and so on. But why does the compiler restrict the problem just for structs? Doesn't the issue persist for class too? Am I missing something?

nawfal
  • 70,104
  • 56
  • 326
  • 368

4 Answers4

21

The problem is in terms of layout.

When Unit is a struct, any value for a Unit would have to contain another value of the same type (and thus the same size), ad infinitum. That's impossible. I suppose you could argue that with no other fields, the fields for Unit should take up no memory, so you could contain it within itself - but I believe the way the CLR works ensures that all structs take up at least 1 byte...

When Unit is a class, a Unit object only has to contain a reference to another Unit object. No storage problems, and the value can be null to start with.

Think of it this way: you can't have a house which contains another house constructed from the same blueprint, but you can certainly have a house which contains a piece of paper with a similar house's address on it...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Jon, the house example is great indeed! :) – nawfal Jan 13 '13 at 23:09
  • 1
    Succinctly explained in the last bit. +1 – Sion Sheevok Jan 13 '13 at 23:09
  • Oh god, when I answer the same question with Jon, my answer looks like pointless. Damn! – Soner Gönül Jan 13 '13 at 23:12
  • 1
    Is it correct to say that the Unit contains itself? It does not contain itself, but contains another Unit. It's just that a Unit contains a Unit contains a Unit... to infinity. – Dave Cousineau Jan 13 '13 at 23:16
  • @Sahuagin yes you're right. Jon might edit it. But the point is driven home anyways :) – nawfal Jan 13 '13 at 23:22
  • 1
    @Sahuagin: Any single value contains another value of the same type. Will edit to make the wording somewhat more bulletproof. – Jon Skeet Jan 13 '13 at 23:23
  • 1
    @Sahuagin: Jon is of course correct; to illustrate the point, consider the built-in structs. You cannot say `struct Int32 { private Int32 value; }` but from the CLR's perspective, an Int32 is precisely a struct whose sole field is an Int32. Obviously in order for that to be sensible, the CLR has to have special knowledge: that an Int32 is four bytes. It has no such special knowledge of the original poster's recursively-defined struct. – Eric Lippert Jan 14 '13 at 02:05
  • @EricLippert: I *very* nearly mentioned that (I started writing the edit then abandoned it), as it came up at CodeMash. I wasn't sure how public that was meant to be though :) – Jon Skeet Jan 14 '13 at 06:51
3

Classes are reference types, so I imagine the difference is that in the class example, it only has to save a reference to another instance. For your struct, a value type, it would need to include the entire structure again, hence an infinite loop.

Paul Phillips
  • 6,093
  • 24
  • 34
2

The struct is automatically initialized with a value, so in your example a Unit value contains a Unit value, which contains a Unit value, which contains a Unit value, etc...

Your class example only initializes the reference to null, which does not have an infinite regress. You would however encounter a similar problem if you did the following:

class Unit
{
   Unit mUnit = new Unit();
}

Now, constructing a Unit constructs a Unit, which constructs a Unit, etc... In this case, you will encounter a runtime stack overflow exception if/when you try to instantiate a Unit object.

I thought that you might be able to avoid the struct issue by using a nullable type, but the problem remains. I believe this is due to the fact that a nullable struct is still instantiated when set to null.

Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80
  • 1
    Both your assumptions are wrong in fact. Edit it. With the first one I mean there isn't any compile time warning like as in for structs. – nawfal Jan 13 '13 at 23:16
  • @nawfal can you be more specific? – Dave Cousineau Jan 13 '13 at 23:18
  • I didn't say you would get a compile time warning I said you'd get a stack overflow, which you do. – Dave Cousineau Jan 13 '13 at 23:19
  • Ok the first code is not so much of an issue because you're talking of something similar (yet different since its a runtime exception). But the second code doesn't compile either. – nawfal Jan 13 '13 at 23:19
  • Please edit the incorrect info. Someone might downvote this otherwise. Nevertheless I see your point and gave me more insight. – nawfal Jan 13 '13 at 23:24
1

Because Struct are value type. Unit can hold the value as itself? I think this is not posible.

But when Unit is class, class are reference type. Unit object can hold a reference to the another Unit object. It is fine.

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364