10

The source-code for System.Boolean at the Reference Source website states that instances of the struct Boolean contain only a single bool field: private bool m_value:

https://referencesource.microsoft.com/#mscorlib/system/boolean.cs,f1b135ff6c380b37

namespace System {

    using System;
    using System.Globalization;
    using System.Diagnostics.Contracts;

    [Serializable]
    [System.Runtime.InteropServices.ComVisible(true)]
    public struct Boolean : IComparable, IConvertible
#if GENERICS_WORK
        , IComparable<Boolean>,  IEquatable<Boolean>
#endif
    {
      private bool m_value;

      internal const int True = 1; 
      internal const int False = 0; 

      internal const String TrueLiteral  = "True";
      internal const String FalseLiteral = "False";

      public static readonly String TrueString  = TrueLiteral;
      public static readonly String FalseString = FalseLiteral;
}

But I noticed that...

  • bool is a C# language alias for System.Boolean.
  • The type is struct Boolean which is a value-type which means it cannot contain itself as a field.
  • ...yet this code presumably compiles.
  • I understand that when the -nostdlib compiler option is set you need to provide your own essential type definitions like System.String, System.Int32, System.Exception - that's the only difference.
  • The published source-code contains no other special attributes like [MethodImpl( MethodImplOptions.InternalCall )].

So how does this code compile?

Dai
  • 141,631
  • 28
  • 261
  • 374
  • 1
    It is a decent demonstration that the common "it is an alias" assumption is a broken mental model. `bool` is a *keyword* in the C# language. Both the compiler and the runtime has a lot of built-in knowledge about the type and don't need help from System.Boolean. The declarations in mscorlib for the primitive value types match the boxed representation of the type. – Hans Passant Dec 06 '19 at 17:03

1 Answers1

3

Short answer: It's a special case, relating to type boxing and their underlying representation. These types are well-known to the compiler and as such are treated slightly differently by core parts of the runtime and the compiler/JIT optimizer compared to regular types.


Since this is buried deep in the runtime implementation, I would presume the language specification would not go into specific runtime implementation details. I'm not sure if this is a satisfactory enough answer but I think in this particular case, the bool type remains unboxed and thus exists as a raw value type as part of the structure.

The semantics of boxing and unboxing of value types are intentionally opaque to make using the language easier. In this case the Boolean structure itself seems to rely on implementation specific boxing rules to implement the actual semantics such as:

  // Determines whether two Boolean objects are equal.
  public override bool Equals (Object obj) {
    //If it's not a boolean, we're definitely not equal
    if (!(obj is Boolean)) {
      return false;
    }

    return (m_value==((Boolean)obj).m_value);
  }

I believe in the above, a boxed structure representing a boolean type is first type-checked followed by it being unboxed and the internal bool value being directly compared. Unlike a boxed type, which may be a tagged pointer or an actual structure with some runtime type information, unboxed types are treated as actual data.

I believe internally, if a bool had to be boxed to be passed off as System.Object (because of type erasure or where no optimization would possible) you would end up with something along the lines of this for true which boxes the value 1.

ldc.i4.1
box        [mscorlib]System.Boolean

So while on a high level bool and System.Boolean appear to be identical and may be optimized similarly, in this particular case within the runtime, the distinctions between the boxed and unboxed versions of bool are directly exposed. Similary, an unboxed bool cannot be compared to System.Object which is inherently a boxed type. This answer regarding the need for boxing/unboxing goes into a lot more depth as far as explaining the principle itself.

In managed languages runtime implementations generally need to be exempt from certain rules when it comes to some core runtime features, this is certainly true for Java and other JVM based languages. While I'm not familiar with CLR as well, I would think the same principle applied here.

While this question about 'bool' being a type alias for 'System.Boolean' essentially covers general use cases, when getting close to the runtime implementation, the dialect of C# becomes more like "implementation specific C#", which can bend the rules slightly.

Kristina
  • 15,859
  • 29
  • 111
  • 181
  • I upvoted this for your insight - but I cannot mark this as the accepted answer because it isn't authoritative, sorry :( – Dai Dec 23 '19 at 00:20