4

Nullable<T> is a struct that has the following definition:

public struct Nullable<T> where T : struct

where struct is a type constraint so that T is constrained to (according to the spec §4.4.4):

  • struct type or enum type
  • not a nullable type.

Looking in the source for Nullable<T> there are no special attributes (expect for [Serializable]), so how does the compiler can recognise it as a "nullable type"?

In response to the comments below:

int is an alias for Int32:

(§4.1.4) simple types are identified through reserved words, but these reserved words are simply aliases for predefined struct types in the System namespace

T? is shorthand for Nullable<T>:

(§4.1.10) - A nullable type is written T?, where T is the underlying type. This syntax is shorthand for System.Nullable, and the two forms can be used interchangeably.

This seems to be a distinct difference which isn't reflected below.

So how does the compiler recognise a simple struct (with no special code) as a "nullable type", struct name?

m.edmondson
  • 30,382
  • 27
  • 123
  • 206
  • Well it's a special type; this is also why the compiler understands "int?" as "Nullable". – ken2k Feb 14 '14 at 10:42
  • You might find [this answer](http://stackoverflow.com/a/2503832/1324810) helpful – Joe Feb 14 '14 at 10:42
  • 1
    @ken2k - I don't agree, that's simply a type alias so the compiler will simply translate `int?` into `Nullable` during compilation – m.edmondson Feb 14 '14 at 10:43
  • @m.edmondson I would say it's not an alias but a syntatic-sugar that is language-dependent. Also, Nullable has specific boxing capabilities that can't normally be defined. – ken2k Feb 14 '14 at 10:50
  • The compiler has to do all kinds of special handling for different types. I'd imagine the compiler "recognizes" `Nullable` in a similar way to the way it recognizes e.g. `Int32`. – Damien_The_Unbeliever Feb 14 '14 at 10:58
  • 1
    The C# compiler certainly has intimate knowledge of Nullables. It for example allows them with the ?? operator and permits lifted conversion operators on them. It is not very clear what particular aspect you are asking about. – Hans Passant Feb 14 '14 at 12:19
  • This seems like similar of my old question about `ValueType` class.See: [What makes ValueType class Special?](http://stackoverflow.com/questions/21213708/what-makes-valuetype-class-special) – Selman Genç Feb 14 '14 at 16:57
  • 1
    @Selman22 - I agree this question is more about "special types" in general. Eric's response of `Are all of these special cases hard coded into the compiler? Yes.` probably answers this question. – m.edmondson Feb 14 '14 at 17:06

1 Answers1

2

Based off of the Shared Source CLI 2.0, Nullable<T> is made "special" via the PREDEFTYPEDEF macro, which takes the name "System.Nullable" and maps it to the attribute PT_G_OPTIONAL which is checked throughout the rest of the compiler.

With regards to the aliases of intSystem.Int32 et al., see the "nice name" column.

From sscli20\csharp\inc\predeftype.h:

//         id            full type name       required  simple     numer    AggKind  fund type   elementtype,      nice name,    zero, quasi simple numer, attribute arg size serialization type,  predef attribute, arity, in mscorlib)
PREDEFTYPEDEF(PT_BYTE,   "System.Byte",         1,            1,      1,     Struct,   FT_U1,   ELEMENT_TYPE_U1,      L"byte",      0,                 0,      1,      SERIALIZATION_TYPE_U1,      PA_COUNT, 0, 1)
PREDEFTYPEDEF(PT_SHORT,  "System.Int16",        1,            1,      1,     Struct,   FT_I2,   ELEMENT_TYPE_I2,      L"short",     0,                 0,      2,      SERIALIZATION_TYPE_I2,      PA_COUNT, 0, 1)
PREDEFTYPEDEF(PT_INT,    "System.Int32",        1,            1,      1,     Struct,   FT_I4,   ELEMENT_TYPE_I4,      L"int",       0,                 0,      4,      SERIALIZATION_TYPE_I4,      PA_COUNT, 0, 1)
PREDEFTYPEDEF(PT_LONG,   "System.Int64",        1,            1,      1,     Struct,   FT_I8,   ELEMENT_TYPE_I8,      L"long",      &longZero,         0,      8,      SERIALIZATION_TYPE_I8,      PA_COUNT, 0, 1)
// ... snip ...
// Nullable<T>
PREDEFTYPEDEF(PT_G_OPTIONAL, "System.Nullable",  0,     0,     0,   Struct,   FT_STRUCT,  ELEMENT_TYPE_END,      NULL,          0,                 0,      0,      0,                          PA_COUNT, 1, 1)

Then its used elsewhere like this:

From sscli20\csharp\sccomp\nullable.cpp:

/***************************************************************************************************
    Return true iff the method is the nullable ctor taking one parameter.
***************************************************************************************************/
bool FUNCBREC::IsNubCtor(METHSYM * meth)
{
    return meth && meth->getClass()->isPredefAgg(PT_G_OPTIONAL) && meth->params->size == 1 &&
        meth->params->Item(0)->isTYVARSYM() && meth->isCtor();
}

For those reading this question, you are probably the target audience for Shared Source CLI 2.0 Internals, which was released as a free e-book.

Mitch
  • 21,223
  • 6
  • 63
  • 86
  • Wow! Amazing answer. So the short answer is indeed that the hardcoded struct name is what identifies `System.Nullable` as special? – m.edmondson Feb 20 '14 at 16:33