Value Type Redux

 

I’d like to thank Yves Dolce for responding to Wesner Moise who writes:

Sender: Wesner Moise

re: Value Type Representation Between the Original and Revised C++

I am not sure that I understand you when you say v.ToString() results in an error, because v needs to be boxed in order to access an inherited method. V does not need to be boxed; indeed, valuetypes are not boxed in VB.NET or C#, when ToString() is called.

Yves dug a bit and wrote the following:

Sender: Yves Dolce

re: Value Type Representation Between the Original and Revised C++

I just tried with C#:

struct Complex

{

   public Complex( double r, double i )

   {

      this.r = r ;

      this.i = i ;

   }

   private double r, i ;

}

...

   Complex c = new Complex( 1, 2 ) ;

   c.ToString() ;

And the IL shows c IS boxed:

IL_000d: ldloca.s c

IL_000f: ldc.r8 1.

IL_0018: ldc.r8 2.

IL_0021: call instance void NeedToBox.Complex::.ctor(float64, float64)

IL_0026: ldloc.0

IL_0027: box NeedToBox.Complex

IL_002c: callvirt instance string [mscorlib]System.ValueType::ToString()

In fact, if memory serves, this particular problem with value types and the contextual need to box them or not was at one time a problem with generics in C#, but I don’t recall the issue. As Yves further documents, in the original C++ with Managed Extensions release,

Sender: Yves Dolce

re: Value Type Representation Between the Original and Revised C++

Wesner,

Try calling ToString() on an instance of:

_value class Complex

{

   public:

      Complex( double r, double i ) : m_r(r), m_i(i) {}

   public:

      //virtual String * ToString() { return String::Format( S"{0} + {1} i", m_r.ToString(), m_i.ToString() ) ; }

   private:

      double m_r,

             m_i ;

} ;

I will fail with:

error C3610: 'Complex': value type must be 'boxed' before method 'ToString' can be called

As I wrote in my original blog entry,

The primary motive behind this design was pedagogical: it wished to make the underlying mechanism visible to the programmer so that she would understand the `cost’ of not providing an instance within her value type. Were V to contain an instance of ToString, the implicit boxing would not be necessary.

In thing2 [yes, referring to the two languages in this way is annoying, isn’t it?], the implicit boxing is carried out transparently:

            v.ToString(); // thing2

but at the cost of possibly encouraging the class designer to introduce an instance of ToString within V. The reason the implicit boxing is preferred is because while there is usually one class designer, there are an unlimited number of users, none of whom would have the freedom to modify V to eliminate the possibly onerous explicit box.

The other reason not to require the explicit boxing is that it requires the programmer to understand what is going on under the hood, and the C# and VB.NET design philosophy is not to burden the user with that level of complexity: not just the boxing that is required, but the use of a virtual table, and the need to locate the pointer for that table for value classes that do not provide an explicit instance, etc. That is a lot of baggage to ask the user to carry for a seemingly simple ToString() invocation!

This kind of dialogue is actually quite refreshing, and something that book-writing does not give rise to. Once again, let me thank Yves!