56

Been browsing through .NET source code of .NET Framework Reference Source, just for fun of it. And found something I don't understand.

There is a Int32.cs file with C# code for Int32 type. And somehow that seems strange to me. How does the C# compiler compile code for Int32 type?

public struct Int32: IComparable, IFormattable, IConvertible {
    internal int m_value;

    // ... 
}

But isn't this illegal in C#? If int is only an alias for Int32, it should fail to compile with Error CS0523:

Struct member 'struct2 field' of type 'struct1' causes a cycle in the struct layout.

Is there some magic in the compiler, or am I completely off track?

Jurica Smircic
  • 6,117
  • 2
  • 22
  • 27
  • 1
    review this http://stackoverflow.com/questions/62503/c-int-or-int32-should-i-care – rummykhan Apr 19 '13 at 21:37
  • 10
    I think the answers so far are missing the true question: "If `Int32` is just an alias for `int`, how can the Int32 class *use* an `int`?" – Tim M. Apr 19 '13 at 21:42
  • 5
    There's some good discussion here about the exact same question: http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/6d183671-2f42-4803-ac08-334d19708bc1/ – mellamokb Apr 19 '13 at 21:50
  • 2
    Agreed with @Tim. That's a good question, probably the one that should be asked in the title. jure, I think an [edit] is in order. – Cody Gray - on strike Apr 20 '13 at 00:03
  • 5
    Built-in types are magic. They have to be - otherwise it'd be turtles all the way down. – harold Apr 20 '13 at 10:31
  • This question is not a duplicate of the stated question. (Perhaps it was before some edits, but it is not now.) – Eric Lippert Apr 22 '13 at 15:27
  • 6
    However, the answer to your question is extremely short. Is there a special case in the compiler to allow for the fact that `System.Int32` has a field of type `System.Int32`, which would normally be an error? Obviously: **yes**. The question practically answers itself; there would normally be an error, there is not an error for the extremely special case of int, therefore there must be a special case in the compiler. And there is. – Eric Lippert Apr 22 '13 at 15:28

2 Answers2

49

isn't this illegal in C#? If "int" is only alias for "Int32" it should fail to compile with error CS0523. Is there some magic in the compiler?

Yes; the error is deliberately suppressed in the compiler. The cycle checker is skipped entirely if the type in question is a built-in type.

Normally this sort of thing is illegal:

struct S { S s; int i; }

In that case the size of S is undefined because whatever the size of S is, it must be equal to itself plus the size of an int. There is no such size.

struct S { S s; }

In that case we have no information from which to deduce the size of S.

struct Int32 { Int32 i; }

But in this case the compiler knows ahead of time that System.Int32 is four bytes because it is a very special type.

Incidentally, the details of how the C# compiler (and, for that matter, the CLR) determines when a set of struct types is cyclic is extremely interesting. I'll try to write a blog article about that at some point.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 5
    Int32 was the very first file I opened when .NET source download was complete. And then the first line shocked me. There’s a line of code in .NET source that shouldn’t be there. After few moments of self-doubt, I came to the conclusion, what you are looking at is code for Int struct, it's like singularity, standard laws of physics don't apply here.. so I closed the file : ) Anyway, looking forward to your blog post, always pleasure to read them. – Jurica Smircic Apr 22 '13 at 20:44
  • @jure: It's more like an electron than a singularity. What are the contents of an electron? One electron! – Eric Lippert Apr 22 '13 at 20:54
  • 1
    I thought the contents of an electron were virtual photons and virtual electron-positron pairs. (Similarly, an Int32 should be defined as `struct Int32 { byte byte1; byte byte2; byte byte3; byte byte4; }` – Mark Cidade Apr 23 '13 at 00:44
  • 1
    Wheres my positron so i can cast int to void! – Jurica Smircic Apr 23 '13 at 07:31
  • 2
    `[StructLayout(LayoutKind.Auto, Size = 4)] struct S { S s; }` would have information to deduce the size of S. But it doesn't feel very useful without special language and compiler support. – Daniel A.A. Pelsmaeker Apr 23 '13 at 13:58
  • @jure - "... so I closed the file" made me laugh :) – Mike Chamberlain Nov 27 '13 at 12:00
  • Mind blown, so Int32 Structure is a structure containing an Int32 type. Cool Microsoft! This, almost doesn't look as a inspector gadget code. – Felype Jun 16 '15 at 13:08
  • 3
    Mr @EricLippert have you written your the article on your blog that you've mentioned? If so, could you share its link? – Soner from The Ottoman Empire Aug 28 '16 at 18:25
13

int is an alias for Int32, but the Int32 struct you are looking at is simply metadata, it is not a real object. The int m_value declaration is possibly there only to give the struct the appropriate size, because it is never actually referenced anywhere else (which is why it is allowed to be there).

So, in other words, the compiler kind of saves this from being a problem. There is a discussion on the topic in the MSDN Forums.

From the discussion, here is a quote from the chosen answer that helps to try to determine how the declaration is possible:

while it is true that the type contains an integer m_value field - the field is never referenced. In every supporting method (CompareTo, ToString, etc), "this" is used instead. It is possible that the m_value fields only exist to force the structures to have the appropriate size.

I suspect that when the compiler sees "int", it translates it into "a reference to System.Int32 in mscorlib.dll, to be resolved later", and since it's building mscorlib.dll, it does end up with a cyclical reference (but not one that can ever cause problems, because m_value is never used). If this assumption is correct, then this trick would only work for special compiler types.

Reading further, it can be determined that the struct is simply metadata, and not a real object, so it is not bound by the same recursive definiton restraints.

John Leehey
  • 22,052
  • 8
  • 61
  • 88
  • I guess if the m_value was declared as Int32 the compile would faile. Interesting discussion on MSDN. At the end, this really doesent matter, but that value types have some strange source code :) – Jurica Smircic Apr 19 '13 at 22:14
  • `System.Int32` is not a class, it's a struct. – svick Apr 22 '13 at 17:12
  • 1
    I think it is worth noting that m_value is used in the source code, quite a bit actually. However the compiler's IL emitter has a special rule that replaces any use of the recursive in a recursive valuetype with a use of the parent object instead. Of course the CLR will refuse not load such a recursive valuetype, except for the built-in ones. – Kevin Cathcart Apr 30 '13 at 19:02